/* Minification failed. Returning unminified contents.
(126480,17-26): run-time error JS1019: Can't have 'break' outside of loop: break OUT
(122279,41-50): run-time error JS1019: Can't have 'break' outside of loop: break OUT
 */
/* NUGET: BEGIN LICENSE TEXT
 *
 * Microsoft grants you the right to use these script files for the sole
 * purpose of either: (i) interacting through your browser with the Microsoft
 * website or online service, subject to the applicable licensing or use
 * terms; or (ii) using the files as included with a Microsoft product subject
 * to that product's license terms. Microsoft reserves all other rights to the
 * files not expressly granted by Microsoft, whether by implication, estoppel
 * or otherwise. Insofar as a script file is dual licensed under GPL,
 * Microsoft neither took the code under GPL nor distributes it thereunder but
 * under the terms set out in this paragraph. All notices and licenses
 * below are for informational purposes only.
 *
 * JQUERY CORE 1.10.2; Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; http://jquery.org/license
 * Includes Sizzle.js; Copyright 2013 jQuery Foundation, Inc. and other contributors; http://opensource.org/licenses/MIT
 *
 * NUGET: END LICENSE TEXT */
/*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
//@ sourceMappingURL=jquery-1.10.2.min.map
*/
(function(e,t){var n,r,i=typeof t,o=e.location,a=e.document,s=a.documentElement,l=e.jQuery,u=e.$,c={},p=[],f="1.10.2",d=p.concat,h=p.push,g=p.slice,m=p.indexOf,y=c.toString,v=c.hasOwnProperty,b=f.trim,x=function(e,t){return new x.fn.init(e,t,r)},w=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,T=/\S+/g,C=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,k=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,E=/^[\],:{}\s]*$/,S=/(?:^|:|,)(?:\s*\[)+/g,A=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,j=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,D=/^-ms-/,L=/-([\da-z])/gi,H=function(e,t){return t.toUpperCase()},q=function(e){(a.addEventListener||"load"===e.type||"complete"===a.readyState)&&(_(),x.ready())},_=function(){a.addEventListener?(a.removeEventListener("DOMContentLoaded",q,!1),e.removeEventListener("load",q,!1)):(a.detachEvent("onreadystatechange",q),e.detachEvent("onload",q))};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,n,r){var i,o;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof x?n[0]:n,x.merge(this,x.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:a,!0)),k.test(i[1])&&x.isPlainObject(n))for(i in n)x.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(o=a.getElementById(i[2]),o&&o.parentNode){if(o.id!==i[2])return r.find(e);this.length=1,this[0]=o}return this.context=a,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return g.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(g.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},l=1,u=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},l=2),"object"==typeof s||x.isFunction(s)||(s={}),u===l&&(s=this,--l);u>l;l++)if(null!=(o=arguments[l]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(x.isPlainObject(r)||(n=x.isArray(r)))?(n?(n=!1,a=e&&x.isArray(e)?e:[]):a=e&&x.isPlainObject(e)?e:{},s[i]=x.extend(c,a,r)):r!==t&&(s[i]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=l),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){if(e===!0?!--x.readyWait:!x.isReady){if(!a.body)return setTimeout(x.ready);x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(a,[x]),x.fn.trigger&&x(a).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray||function(e){return"array"===x.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?c[y.call(e)]||"object":typeof e},isPlainObject:function(e){var n;if(!e||"object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!v.call(e,"constructor")&&!v.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(r){return!1}if(x.support.ownLast)for(n in e)return v.call(e,n);for(n in e);return n===t||v.call(e,n)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||a;var r=k.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=x.trim(n),n&&E.test(n.replace(A,"@").replace(j,"]").replace(S,"")))?Function("return "+n)():(x.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||x.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&x.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(D,"ms-").replace(L,H)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,a=M(e);if(n){if(a){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(a){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:b&&!b.call("\ufeff\u00a0")?function(e){return null==e?"":b.call(e)}:function(e){return null==e?"":(e+"").replace(C,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(M(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){var r;if(t){if(m)return m.call(t,e,n);for(r=t.length,n=n?0>n?Math.max(0,r+n):n:0;r>n;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=n.length,i=e.length,o=0;if("number"==typeof r)for(;r>o;o++)e[i++]=n[o];else while(n[o]!==t)e[i++]=n[o++];return e.length=i,e},grep:function(e,t,n){var r,i=[],o=0,a=e.length;for(n=!!n;a>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,a=M(e),s=[];if(a)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(s[s.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(s[s.length]=r);return d.apply([],s)},guid:1,proxy:function(e,n){var r,i,o;return"string"==typeof n&&(o=e[n],n=e,e=o),x.isFunction(e)?(r=g.call(arguments,2),i=function(){return e.apply(n||this,r.concat(g.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):t},access:function(e,n,r,i,o,a,s){var l=0,u=e.length,c=null==r;if("object"===x.type(r)){o=!0;for(l in r)x.access(e,n,l,r[l],!0,a,s)}else if(i!==t&&(o=!0,x.isFunction(i)||(s=!0),c&&(s?(n.call(e,i),n=null):(c=n,n=function(e,t,n){return c.call(x(e),n)})),n))for(;u>l;l++)n(e[l],r,s?i:i.call(e[l],l,n(e[l],r)));return o?e:c?n.call(e):u?n(e[0],r):a},now:function(){return(new Date).getTime()},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),x.ready.promise=function(t){if(!n)if(n=x.Deferred(),"complete"===a.readyState)setTimeout(x.ready);else if(a.addEventListener)a.addEventListener("DOMContentLoaded",q,!1),e.addEventListener("load",q,!1);else{a.attachEvent("onreadystatechange",q),e.attachEvent("onload",q);var r=!1;try{r=null==e.frameElement&&a.documentElement}catch(i){}r&&r.doScroll&&function o(){if(!x.isReady){try{r.doScroll("left")}catch(e){return setTimeout(o,50)}_(),x.ready()}}()}return n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){c["[object "+t+"]"]=t.toLowerCase()});function M(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}r=x(a),function(e,t){var n,r,i,o,a,s,l,u,c,p,f,d,h,g,m,y,v,b="sizzle"+-new Date,w=e.document,T=0,C=0,N=st(),k=st(),E=st(),S=!1,A=function(e,t){return e===t?(S=!0,0):0},j=typeof t,D=1<<31,L={}.hasOwnProperty,H=[],q=H.pop,_=H.push,M=H.push,O=H.slice,F=H.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},B="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",P="[\\x20\\t\\r\\n\\f]",R="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=R.replace("w","w#"),$="\\["+P+"*("+R+")"+P+"*(?:([*^$|!~]?=)"+P+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+P+"*\\]",I=":("+R+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+P+"+|((?:^|[^\\\\])(?:\\\\.)*)"+P+"+$","g"),X=RegExp("^"+P+"*,"+P+"*"),U=RegExp("^"+P+"*([>+~]|"+P+")"+P+"*"),V=RegExp(P+"*[+~]"),Y=RegExp("="+P+"*([^\\]'\"]*)"+P+"*\\]","g"),J=RegExp(I),G=RegExp("^"+W+"$"),Q={ID:RegExp("^#("+R+")"),CLASS:RegExp("^\\.("+R+")"),TAG:RegExp("^("+R.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+P+"*(even|odd|(([+-]|)(\\d*)n|)"+P+"*(?:([+-]|)"+P+"*(\\d+)|))"+P+"*\\)|)","i"),bool:RegExp("^(?:"+B+")$","i"),needsContext:RegExp("^"+P+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+P+"*((?:-\\d)?\\d*)"+P+"*\\)|)(?=[^-]|$)","i")},K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,et=/^(?:input|select|textarea|button)$/i,tt=/^h\d$/i,nt=/'|\\/g,rt=RegExp("\\\\([\\da-f]{1,6}"+P+"?|("+P+")|.)","ig"),it=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{M.apply(H=O.call(w.childNodes),w.childNodes),H[w.childNodes.length].nodeType}catch(ot){M={apply:H.length?function(e,t){_.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function at(e,t,n,i){var o,a,s,l,u,c,d,m,y,x;if((t?t.ownerDocument||t:w)!==f&&p(t),t=t||f,n=n||[],!e||"string"!=typeof e)return n;if(1!==(l=t.nodeType)&&9!==l)return[];if(h&&!i){if(o=Z.exec(e))if(s=o[1]){if(9===l){if(a=t.getElementById(s),!a||!a.parentNode)return n;if(a.id===s)return n.push(a),n}else if(t.ownerDocument&&(a=t.ownerDocument.getElementById(s))&&v(t,a)&&a.id===s)return n.push(a),n}else{if(o[2])return M.apply(n,t.getElementsByTagName(e)),n;if((s=o[3])&&r.getElementsByClassName&&t.getElementsByClassName)return M.apply(n,t.getElementsByClassName(s)),n}if(r.qsa&&(!g||!g.test(e))){if(m=d=b,y=t,x=9===l&&e,1===l&&"object"!==t.nodeName.toLowerCase()){c=mt(e),(d=t.getAttribute("id"))?m=d.replace(nt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",u=c.length;while(u--)c[u]=m+yt(c[u]);y=V.test(e)&&t.parentNode||t,x=c.join(",")}if(x)try{return M.apply(n,y.querySelectorAll(x)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,n,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>o.cacheLength&&delete t[e.shift()],t[n]=r}return t}function lt(e){return e[b]=!0,e}function ut(e){var t=f.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ct(e,t){var n=e.split("|"),r=e.length;while(r--)o.attrHandle[n[r]]=t}function pt(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function dt(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return lt(function(t){return t=+t,lt(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}s=at.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},r=at.support={},p=at.setDocument=function(e){var n=e?e.ownerDocument||e:w,i=n.defaultView;return n!==f&&9===n.nodeType&&n.documentElement?(f=n,d=n.documentElement,h=!s(n),i&&i.attachEvent&&i!==i.top&&i.attachEvent("onbeforeunload",function(){p()}),r.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),r.getElementsByTagName=ut(function(e){return e.appendChild(n.createComment("")),!e.getElementsByTagName("*").length}),r.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),r.getById=ut(function(e){return d.appendChild(e).id=b,!n.getElementsByName||!n.getElementsByName(b).length}),r.getById?(o.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){return e.getAttribute("id")===t}}):(delete o.find.ID,o.filter.ID=function(e){var t=e.replace(rt,it);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),o.find.TAG=r.getElementsByTagName?function(e,n){return typeof n.getElementsByTagName!==j?n.getElementsByTagName(e):t}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},o.find.CLASS=r.getElementsByClassName&&function(e,n){return typeof n.getElementsByClassName!==j&&h?n.getElementsByClassName(e):t},m=[],g=[],(r.qsa=K.test(n.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||g.push("\\["+P+"*(?:value|"+B+")"),e.querySelectorAll(":checked").length||g.push(":checked")}),ut(function(e){var t=n.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&g.push("[*^$]="+P+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||g.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),g.push(",.*:")})),(r.matchesSelector=K.test(y=d.webkitMatchesSelector||d.mozMatchesSelector||d.oMatchesSelector||d.msMatchesSelector))&&ut(function(e){r.disconnectedMatch=y.call(e,"div"),y.call(e,"[s!='']:x"),m.push("!=",I)}),g=g.length&&RegExp(g.join("|")),m=m.length&&RegExp(m.join("|")),v=K.test(d.contains)||d.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},A=d.compareDocumentPosition?function(e,t){if(e===t)return S=!0,0;var i=t.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(t);return i?1&i||!r.sortDetached&&t.compareDocumentPosition(e)===i?e===n||v(w,e)?-1:t===n||v(w,t)?1:c?F.call(c,e)-F.call(c,t):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,t){var r,i=0,o=e.parentNode,a=t.parentNode,s=[e],l=[t];if(e===t)return S=!0,0;if(!o||!a)return e===n?-1:t===n?1:o?-1:a?1:c?F.call(c,e)-F.call(c,t):0;if(o===a)return pt(e,t);r=e;while(r=r.parentNode)s.unshift(r);r=t;while(r=r.parentNode)l.unshift(r);while(s[i]===l[i])i++;return i?pt(s[i],l[i]):s[i]===w?-1:l[i]===w?1:0},n):f},at.matches=function(e,t){return at(e,null,null,t)},at.matchesSelector=function(e,t){if((e.ownerDocument||e)!==f&&p(e),t=t.replace(Y,"='$1']"),!(!r.matchesSelector||!h||m&&m.test(t)||g&&g.test(t)))try{var n=y.call(e,t);if(n||r.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(i){}return at(t,f,null,[e]).length>0},at.contains=function(e,t){return(e.ownerDocument||e)!==f&&p(e),v(e,t)},at.attr=function(e,n){(e.ownerDocument||e)!==f&&p(e);var i=o.attrHandle[n.toLowerCase()],a=i&&L.call(o.attrHandle,n.toLowerCase())?i(e,n,!h):t;return a===t?r.attributes||!h?e.getAttribute(n):(a=e.getAttributeNode(n))&&a.specified?a.value:null:a},at.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},at.uniqueSort=function(e){var t,n=[],i=0,o=0;if(S=!r.detectDuplicates,c=!r.sortStable&&e.slice(0),e.sort(A),S){while(t=e[o++])t===e[o]&&(i=n.push(o));while(i--)e.splice(n[i],1)}return e},a=at.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=a(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=a(t);return n},o=at.selectors={cacheLength:50,createPseudo:lt,match:Q,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(rt,it),e[3]=(e[4]||e[5]||"").replace(rt,it),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||at.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&at.error(e[0]),e},PSEUDO:function(e){var n,r=!e[5]&&e[2];return Q.CHILD.test(e[0])?null:(e[3]&&e[4]!==t?e[2]=e[4]:r&&J.test(r)&&(n=mt(r,!0))&&(n=r.indexOf(")",r.length-n)-r.length)&&(e[0]=e[0].slice(0,n),e[2]=r.slice(0,n)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(rt,it).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=N[e+" "];return t||(t=RegExp("(^|"+P+")"+e+"("+P+"|$)"))&&N(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=at.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,l){var u,c,p,f,d,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!l&&!s;if(m){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){c=m[b]||(m[b]={}),u=c[e]||[],d=u[0]===T&&u[1],f=u[0]===T&&u[2],p=d&&m.childNodes[d];while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[T,d,f];break}}else if(v&&(u=(t[b]||(t[b]={}))[e])&&u[0]===T)f=u[1];else while(p=++d&&p&&p[g]||(f=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(v&&((p[b]||(p[b]={}))[e]=[T,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=o.pseudos[e]||o.setFilters[e.toLowerCase()]||at.error("unsupported pseudo: "+e);return r[b]?r(t):r.length>1?(n=[e,e,"",t],o.setFilters.hasOwnProperty(e.toLowerCase())?lt(function(e,n){var i,o=r(e,t),a=o.length;while(a--)i=F.call(e,o[a]),e[i]=!(n[i]=o[a])}):function(e){return r(e,0,n)}):r}},pseudos:{not:lt(function(e){var t=[],n=[],r=l(e.replace(z,"$1"));return r[b]?lt(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:lt(function(e){return function(t){return at(e,t).length>0}}),contains:lt(function(e){return function(t){return(t.textContent||t.innerText||a(t)).indexOf(e)>-1}}),lang:lt(function(e){return G.test(e||"")||at.error("unsupported lang: "+e),e=e.replace(rt,it).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===d},focus:function(e){return e===f.activeElement&&(!f.hasFocus||f.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!o.pseudos.empty(e)},header:function(e){return tt.test(e.nodeName)},input:function(e){return et.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},o.pseudos.nth=o.pseudos.eq;for(n in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})o.pseudos[n]=ft(n);for(n in{submit:!0,reset:!0})o.pseudos[n]=dt(n);function gt(){}gt.prototype=o.filters=o.pseudos,o.setFilters=new gt;function mt(e,t){var n,r,i,a,s,l,u,c=k[e+" "];if(c)return t?0:c.slice(0);s=e,l=[],u=o.preFilter;while(s){(!n||(r=X.exec(s)))&&(r&&(s=s.slice(r[0].length)||s),l.push(i=[])),n=!1,(r=U.exec(s))&&(n=r.shift(),i.push({value:n,type:r[0].replace(z," ")}),s=s.slice(n.length));for(a in o.filter)!(r=Q[a].exec(s))||u[a]&&!(r=u[a](r))||(n=r.shift(),i.push({value:n,type:a,matches:r}),s=s.slice(n.length));if(!n)break}return t?s.length:s?at.error(e):k(e,l).slice(0)}function yt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function vt(e,t,n){var r=t.dir,o=n&&"parentNode"===r,a=C++;return t.first?function(t,n,i){while(t=t[r])if(1===t.nodeType||o)return e(t,n,i)}:function(t,n,s){var l,u,c,p=T+" "+a;if(s){while(t=t[r])if((1===t.nodeType||o)&&e(t,n,s))return!0}else while(t=t[r])if(1===t.nodeType||o)if(c=t[b]||(t[b]={}),(u=c[r])&&u[0]===p){if((l=u[1])===!0||l===i)return l===!0}else if(u=c[r]=[p],u[1]=e(t,n,s)||i,u[1]===!0)return!0}}function bt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,a=[],s=0,l=e.length,u=null!=t;for(;l>s;s++)(o=e[s])&&(!n||n(o,r,i))&&(a.push(o),u&&t.push(s));return a}function wt(e,t,n,r,i,o){return r&&!r[b]&&(r=wt(r)),i&&!i[b]&&(i=wt(i,o)),lt(function(o,a,s,l){var u,c,p,f=[],d=[],h=a.length,g=o||Nt(t||"*",s.nodeType?[s]:s,[]),m=!e||!o&&t?g:xt(g,f,e,s,l),y=n?i||(o?e:h||r)?[]:a:m;if(n&&n(m,y,s,l),r){u=xt(y,d),r(u,[],s,l),c=u.length;while(c--)(p=u[c])&&(y[d[c]]=!(m[d[c]]=p))}if(o){if(i||e){if(i){u=[],c=y.length;while(c--)(p=y[c])&&u.push(m[c]=p);i(null,y=[],u,l)}c=y.length;while(c--)(p=y[c])&&(u=i?F.call(o,p):f[c])>-1&&(o[u]=!(a[u]=p))}}else y=xt(y===a?y.splice(h,y.length):y),i?i(null,a,y,l):M.apply(a,y)})}function Tt(e){var t,n,r,i=e.length,a=o.relative[e[0].type],s=a||o.relative[" "],l=a?1:0,c=vt(function(e){return e===t},s,!0),p=vt(function(e){return F.call(t,e)>-1},s,!0),f=[function(e,n,r){return!a&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;i>l;l++)if(n=o.relative[e[l].type])f=[vt(bt(f),n)];else{if(n=o.filter[e[l].type].apply(null,e[l].matches),n[b]){for(r=++l;i>r;r++)if(o.relative[e[r].type])break;return wt(l>1&&bt(f),l>1&&yt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&Tt(e.slice(l,r)),i>r&&Tt(e=e.slice(r)),i>r&&yt(e))}f.push(n)}return bt(f)}function Ct(e,t){var n=0,r=t.length>0,a=e.length>0,s=function(s,l,c,p,d){var h,g,m,y=[],v=0,b="0",x=s&&[],w=null!=d,C=u,N=s||a&&o.find.TAG("*",d&&l.parentNode||l),k=T+=null==C?1:Math.random()||.1;for(w&&(u=l!==f&&l,i=n);null!=(h=N[b]);b++){if(a&&h){g=0;while(m=e[g++])if(m(h,l,c)){p.push(h);break}w&&(T=k,i=++n)}r&&((h=!m&&h)&&v--,s&&x.push(h))}if(v+=b,r&&b!==v){g=0;while(m=t[g++])m(x,y,l,c);if(s){if(v>0)while(b--)x[b]||y[b]||(y[b]=q.call(p));y=xt(y)}M.apply(p,y),w&&!s&&y.length>0&&v+t.length>1&&at.uniqueSort(p)}return w&&(T=k,u=C),x};return r?lt(s):s}l=at.compile=function(e,t){var n,r=[],i=[],o=E[e+" "];if(!o){t||(t=mt(e)),n=t.length;while(n--)o=Tt(t[n]),o[b]?r.push(o):i.push(o);o=E(e,Ct(i,r))}return o};function Nt(e,t,n){var r=0,i=t.length;for(;i>r;r++)at(e,t[r],n);return n}function kt(e,t,n,i){var a,s,u,c,p,f=mt(e);if(!i&&1===f.length){if(s=f[0]=f[0].slice(0),s.length>2&&"ID"===(u=s[0]).type&&r.getById&&9===t.nodeType&&h&&o.relative[s[1].type]){if(t=(o.find.ID(u.matches[0].replace(rt,it),t)||[])[0],!t)return n;e=e.slice(s.shift().value.length)}a=Q.needsContext.test(e)?0:s.length;while(a--){if(u=s[a],o.relative[c=u.type])break;if((p=o.find[c])&&(i=p(u.matches[0].replace(rt,it),V.test(s[0].type)&&t.parentNode||t))){if(s.splice(a,1),e=i.length&&yt(s),!e)return M.apply(n,i),n;break}}}return l(e,f)(i,t,!h,n,V.test(e)),n}r.sortStable=b.split("").sort(A).join("")===b,r.detectDuplicates=S,p(),r.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(f.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||ct("type|href|height|width",function(e,n,r){return r?t:e.getAttribute(n,"type"===n.toLowerCase()?1:2)}),r.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||ct("value",function(e,n,r){return r||"input"!==e.nodeName.toLowerCase()?t:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||ct(B,function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&i.specified?i.value:e[n]===!0?n.toLowerCase():null}),x.find=at,x.expr=at.selectors,x.expr[":"]=x.expr.pseudos,x.unique=at.uniqueSort,x.text=at.getText,x.isXMLDoc=at.isXML,x.contains=at.contains}(e);var O={};function F(e){var t=O[e]={};return x.each(e.match(T)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?O[e]||F(e):x.extend({},e);var n,r,i,o,a,s,l=[],u=!e.once&&[],c=function(t){for(r=e.memory&&t,i=!0,a=s||0,s=0,o=l.length,n=!0;l&&o>a;a++)if(l[a].apply(t[0],t[1])===!1&&e.stopOnFalse){r=!1;break}n=!1,l&&(u?u.length&&c(u.shift()):r?l=[]:p.disable())},p={add:function(){if(l){var t=l.length;(function i(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&p.has(n)||l.push(n):n&&n.length&&"string"!==r&&i(n)})})(arguments),n?o=l.length:r&&(s=t,c(r))}return this},remove:function(){return l&&x.each(arguments,function(e,t){var r;while((r=x.inArray(t,l,r))>-1)l.splice(r,1),n&&(o>=r&&o--,a>=r&&a--)}),this},has:function(e){return e?x.inArray(e,l)>-1:!(!l||!l.length)},empty:function(){return l=[],o=0,this},disable:function(){return l=u=r=t,this},disabled:function(){return!l},lock:function(){return u=t,r||p.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!l||i&&!u||(t=t||[],t=[e,t.slice?t.slice():t],n?u.push(t):c(t)),this},fire:function(){return p.fireWith(this,arguments),this},fired:function(){return!!i}};return p},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var a=o[0],s=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=s&&s.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[a+"With"](this===r?n.promise():this,s?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=g.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),a=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?g.call(arguments):r,n===s?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},s,l,u;if(r>1)for(s=Array(r),l=Array(r),u=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(a(t,u,n)).fail(o.reject).progress(a(t,l,s)):--i;return i||o.resolveWith(u,n),o.promise()}}),x.support=function(t){var n,r,o,s,l,u,c,p,f,d=a.createElement("div");if(d.setAttribute("className","t"),d.innerHTML="  <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",n=d.getElementsByTagName("*")||[],r=d.getElementsByTagName("a")[0],!r||!r.style||!n.length)return t;s=a.createElement("select"),u=s.appendChild(a.createElement("option")),o=d.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t.getSetAttribute="t"!==d.className,t.leadingWhitespace=3===d.firstChild.nodeType,t.tbody=!d.getElementsByTagName("tbody").length,t.htmlSerialize=!!d.getElementsByTagName("link").length,t.style=/top/.test(r.getAttribute("style")),t.hrefNormalized="/a"===r.getAttribute("href"),t.opacity=/^0.5/.test(r.style.opacity),t.cssFloat=!!r.style.cssFloat,t.checkOn=!!o.value,t.optSelected=u.selected,t.enctype=!!a.createElement("form").enctype,t.html5Clone="<:nav></:nav>"!==a.createElement("nav").cloneNode(!0).outerHTML,t.inlineBlockNeedsLayout=!1,t.shrinkWrapBlocks=!1,t.pixelPosition=!1,t.deleteExpando=!0,t.noCloneEvent=!0,t.reliableMarginRight=!0,t.boxSizingReliable=!0,o.checked=!0,t.noCloneChecked=o.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!u.disabled;try{delete d.test}catch(h){t.deleteExpando=!1}o=a.createElement("input"),o.setAttribute("value",""),t.input=""===o.getAttribute("value"),o.value="t",o.setAttribute("type","radio"),t.radioValue="t"===o.value,o.setAttribute("checked","t"),o.setAttribute("name","t"),l=a.createDocumentFragment(),l.appendChild(o),t.appendChecked=o.checked,t.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,d.attachEvent&&(d.attachEvent("onclick",function(){t.noCloneEvent=!1}),d.cloneNode(!0).click());for(f in{submit:!0,change:!0,focusin:!0})d.setAttribute(c="on"+f,"t"),t[f+"Bubbles"]=c in e||d.attributes[c].expando===!1;d.style.backgroundClip="content-box",d.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===d.style.backgroundClip;for(f in x(t))break;return t.ownLast="0"!==f,x(function(){var n,r,o,s="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",l=a.getElementsByTagName("body")[0];l&&(n=a.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",l.appendChild(n).appendChild(d),d.innerHTML="<table><tr><td></td><td>t</td></tr></table>",o=d.getElementsByTagName("td"),o[0].style.cssText="padding:0;margin:0;border:0;display:none",p=0===o[0].offsetHeight,o[0].style.display="",o[1].style.display="none",t.reliableHiddenOffsets=p&&0===o[0].offsetHeight,d.innerHTML="",d.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",x.swap(l,null!=l.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===d.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(d,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(d,null)||{width:"4px"}).width,r=d.appendChild(a.createElement("div")),r.style.cssText=d.style.cssText=s,r.style.marginRight=r.style.width="0",d.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),typeof d.style.zoom!==i&&(d.innerHTML="",d.style.cssText=s+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=3===d.offsetWidth,d.style.display="block",d.innerHTML="<div></div>",d.firstChild.style.width="5px",t.shrinkWrapBlocks=3!==d.offsetWidth,t.inlineBlockNeedsLayout&&(l.style.zoom=1)),l.removeChild(n),n=d=o=r=null)}),n=s=l=u=r=o=null,t
}({});var B=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;function R(e,n,r,i){if(x.acceptData(e)){var o,a,s=x.expando,l=e.nodeType,u=l?x.cache:e,c=l?e[s]:e[s]&&s;if(c&&u[c]&&(i||u[c].data)||r!==t||"string"!=typeof n)return c||(c=l?e[s]=p.pop()||x.guid++:s),u[c]||(u[c]=l?{}:{toJSON:x.noop}),("object"==typeof n||"function"==typeof n)&&(i?u[c]=x.extend(u[c],n):u[c].data=x.extend(u[c].data,n)),a=u[c],i||(a.data||(a.data={}),a=a.data),r!==t&&(a[x.camelCase(n)]=r),"string"==typeof n?(o=a[n],null==o&&(o=a[x.camelCase(n)])):o=a,o}}function W(e,t,n){if(x.acceptData(e)){var r,i,o=e.nodeType,a=o?x.cache:e,s=o?e[x.expando]:x.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){x.isArray(t)?t=t.concat(x.map(t,x.camelCase)):t in r?t=[t]:(t=x.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;while(i--)delete r[t[i]];if(n?!I(r):!x.isEmptyObject(r))return}(n||(delete a[s].data,I(a[s])))&&(o?x.cleanData([e],!0):x.support.deleteExpando||a!=a.window?delete a[s]:a[s]=null)}}}x.extend({cache:{},noData:{applet:!0,embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?x.cache[e[x.expando]]:e[x.expando],!!e&&!I(e)},data:function(e,t,n){return R(e,t,n)},removeData:function(e,t){return W(e,t)},_data:function(e,t,n){return R(e,t,n,!0)},_removeData:function(e,t){return W(e,t,!0)},acceptData:function(e){if(e.nodeType&&1!==e.nodeType&&9!==e.nodeType)return!1;var t=e.nodeName&&x.noData[e.nodeName.toLowerCase()];return!t||t!==!0&&e.getAttribute("classid")===t}}),x.fn.extend({data:function(e,n){var r,i,o=null,a=0,s=this[0];if(e===t){if(this.length&&(o=x.data(s),1===s.nodeType&&!x._data(s,"parsedAttrs"))){for(r=s.attributes;r.length>a;a++)i=r[a].name,0===i.indexOf("data-")&&(i=x.camelCase(i.slice(5)),$(s,i,o[i]));x._data(s,"parsedAttrs",!0)}return o}return"object"==typeof e?this.each(function(){x.data(this,e)}):arguments.length>1?this.each(function(){x.data(this,e,n)}):s?$(s,e,x.data(s,e)):null},removeData:function(e){return this.each(function(){x.removeData(this,e)})}});function $(e,n,r){if(r===t&&1===e.nodeType){var i="data-"+n.replace(P,"-$1").toLowerCase();if(r=e.getAttribute(i),"string"==typeof r){try{r="true"===r?!0:"false"===r?!1:"null"===r?null:+r+""===r?+r:B.test(r)?x.parseJSON(r):r}catch(o){}x.data(e,n,r)}else r=t}return r}function I(e){var t;for(t in e)if(("data"!==t||!x.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}x.extend({queue:function(e,n,r){var i;return e?(n=(n||"fx")+"queue",i=x._data(e,n),r&&(!i||x.isArray(r)?i=x._data(e,n,x.makeArray(r)):i.push(r)),i||[]):t},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),a=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return x._data(e,n)||x._data(e,n,{empty:x.Callbacks("once memory").add(function(){x._removeData(e,t+"queue"),x._removeData(e,n)})})}}),x.fn.extend({queue:function(e,n){var r=2;return"string"!=typeof e&&(n=e,e="fx",r--),r>arguments.length?x.queue(this[0],e):n===t?this:this.each(function(){var t=x.queue(this,e,n);x._queueHooks(this,e),"fx"===e&&"inprogress"!==t[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){var r,i=1,o=x.Deferred(),a=this,s=this.length,l=function(){--i||o.resolveWith(a,[a])};"string"!=typeof e&&(n=e,e=t),e=e||"fx";while(s--)r=x._data(a[s],e+"queueHooks"),r&&r.empty&&(i++,r.empty.add(l));return l(),o.promise(n)}});var z,X,U=/[\t\r\n\f]/g,V=/\r/g,Y=/^(?:input|select|textarea|button|object)$/i,J=/^(?:a|area)$/i,G=/^(?:checked|selected)$/i,Q=x.support.getSetAttribute,K=x.support.input;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return e=x.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,a=0,s=this.length,l="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,a=0,s=this.length,l=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(l)for(t=(e||"").match(T)||[];s>a;a++)if(n=this[a],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(U," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,r=0,o=x(this),a=e.match(T)||[];while(t=a[r++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===i||"boolean"===n)&&(this.className&&x._data(this,"__className__",this.className),this.className=this.className||e===!1?"":x._data(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(U," ").indexOf(t)>=0)return!0;return!1},val:function(e){var n,r,i,o=this[0];{if(arguments.length)return i=x.isFunction(e),this.each(function(n){var o;1===this.nodeType&&(o=i?e.call(this,n,x(this).val()):e,null==o?o="":"number"==typeof o?o+="":x.isArray(o)&&(o=x.map(o,function(e){return null==e?"":e+""})),r=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],r&&"set"in r&&r.set(this,o,"value")!==t||(this.value=o))});if(o)return r=x.valHooks[o.type]||x.valHooks[o.nodeName.toLowerCase()],r&&"get"in r&&(n=r.get(o,"value"))!==t?n:(n=o.value,"string"==typeof n?n.replace(V,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=x.find.attr(e,"value");return null!=t?t:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,a=o?null:[],s=o?i+1:r.length,l=0>i?s:o?i:0;for(;s>l;l++)if(n=r[l],!(!n.selected&&l!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;a.push(t)}return a},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),a=i.length;while(a--)r=i[a],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,n,r){var o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===i?x.prop(e,n,r):(1===s&&x.isXMLDoc(e)||(n=n.toLowerCase(),o=x.attrHooks[n]||(x.expr.match.bool.test(n)?X:z)),r===t?o&&"get"in o&&null!==(a=o.get(e,n))?a:(a=x.find.attr(e,n),null==a?t:a):null!==r?o&&"set"in o&&(a=o.set(e,r,n))!==t?a:(e.setAttribute(n,r+""),r):(x.removeAttr(e,n),t))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(T);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)?K&&Q||!G.test(n)?e[r]=!1:e[x.camelCase("default-"+n)]=e[r]=!1:x.attr(e,n,""),e.removeAttribute(Q?n:r)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,n,r){var i,o,a,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return a=1!==s||!x.isXMLDoc(e),a&&(n=x.propFix[n]||n,o=x.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&null!==(i=o.get(e,n))?i:e[n]},propHooks:{tabIndex:{get:function(e){var t=x.find.attr(e,"tabindex");return t?parseInt(t,10):Y.test(e.nodeName)||J.test(e.nodeName)&&e.href?0:-1}}}}),X={set:function(e,t,n){return t===!1?x.removeAttr(e,n):K&&Q||!G.test(n)?e.setAttribute(!Q&&x.propFix[n]||n,n):e[x.camelCase("default-"+n)]=e[n]=!0,n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,n){var r=x.expr.attrHandle[n]||x.find.attr;x.expr.attrHandle[n]=K&&Q||!G.test(n)?function(e,n,i){var o=x.expr.attrHandle[n],a=i?t:(x.expr.attrHandle[n]=t)!=r(e,n,i)?n.toLowerCase():null;return x.expr.attrHandle[n]=o,a}:function(e,n,r){return r?t:e[x.camelCase("default-"+n)]?n.toLowerCase():null}}),K&&Q||(x.attrHooks.value={set:function(e,n,r){return x.nodeName(e,"input")?(e.defaultValue=n,t):z&&z.set(e,n,r)}}),Q||(z={set:function(e,n,r){var i=e.getAttributeNode(r);return i||e.setAttributeNode(i=e.ownerDocument.createAttribute(r)),i.value=n+="","value"===r||n===e.getAttribute(r)?n:t}},x.expr.attrHandle.id=x.expr.attrHandle.name=x.expr.attrHandle.coords=function(e,n,r){var i;return r?t:(i=e.getAttributeNode(n))&&""!==i.value?i.value:null},x.valHooks.button={get:function(e,n){var r=e.getAttributeNode(n);return r&&r.specified?r.value:t},set:z.set},x.attrHooks.contenteditable={set:function(e,t,n){z.set(e,""===t?!1:t,n)}},x.each(["width","height"],function(e,n){x.attrHooks[n]={set:function(e,r){return""===r?(e.setAttribute(n,"auto"),r):t}}})),x.support.hrefNormalized||x.each(["href","src"],function(e,t){x.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),x.support.style||(x.attrHooks.style={get:function(e){return e.style.cssText||t},set:function(e,t){return e.style.cssText=t+""}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.support.enctype||(x.propFix.enctype="encoding"),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,n){return x.isArray(n)?e.checked=x.inArray(x(e).val(),n)>=0:t}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Z=/^(?:input|select|textarea)$/i,et=/^key/,tt=/^(?:mouse|contextmenu)|click/,nt=/^(?:focusinfocus|focusoutblur)$/,rt=/^([^.]*)(?:\.(.+)|)$/;function it(){return!0}function ot(){return!1}function at(){try{return a.activeElement}catch(e){}}x.event={global:{},add:function(e,n,r,o,a){var s,l,u,c,p,f,d,h,g,m,y,v=x._data(e);if(v){r.handler&&(c=r,r=c.handler,a=c.selector),r.guid||(r.guid=x.guid++),(l=v.events)||(l=v.events={}),(f=v.handle)||(f=v.handle=function(e){return typeof x===i||e&&x.event.triggered===e.type?t:x.event.dispatch.apply(f.elem,arguments)},f.elem=e),n=(n||"").match(T)||[""],u=n.length;while(u--)s=rt.exec(n[u])||[],g=y=s[1],m=(s[2]||"").split(".").sort(),g&&(p=x.event.special[g]||{},g=(a?p.delegateType:p.bindType)||g,p=x.event.special[g]||{},d=x.extend({type:g,origType:y,data:o,handler:r,guid:r.guid,selector:a,needsContext:a&&x.expr.match.needsContext.test(a),namespace:m.join(".")},c),(h=l[g])||(h=l[g]=[],h.delegateCount=0,p.setup&&p.setup.call(e,o,m,f)!==!1||(e.addEventListener?e.addEventListener(g,f,!1):e.attachEvent&&e.attachEvent("on"+g,f))),p.add&&(p.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),a?h.splice(h.delegateCount++,0,d):h.push(d),x.event.global[g]=!0);e=null}},remove:function(e,t,n,r,i){var o,a,s,l,u,c,p,f,d,h,g,m=x.hasData(e)&&x._data(e);if(m&&(c=m.events)){t=(t||"").match(T)||[""],u=t.length;while(u--)if(s=rt.exec(t[u])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){p=x.event.special[d]||{},d=(r?p.delegateType:p.bindType)||d,f=c[d]||[],s=s[2]&&RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),l=o=f.length;while(o--)a=f[o],!i&&g!==a.origType||n&&n.guid!==a.guid||s&&!s.test(a.namespace)||r&&r!==a.selector&&("**"!==r||!a.selector)||(f.splice(o,1),a.selector&&f.delegateCount--,p.remove&&p.remove.call(e,a));l&&!f.length&&(p.teardown&&p.teardown.call(e,h,m.handle)!==!1||x.removeEvent(e,d,m.handle),delete c[d])}else for(d in c)x.event.remove(e,d+t[u],n,r,!0);x.isEmptyObject(c)&&(delete m.handle,x._removeData(e,"events"))}},trigger:function(n,r,i,o){var s,l,u,c,p,f,d,h=[i||a],g=v.call(n,"type")?n.type:n,m=v.call(n,"namespace")?n.namespace.split("."):[];if(u=f=i=i||a,3!==i.nodeType&&8!==i.nodeType&&!nt.test(g+x.event.triggered)&&(g.indexOf(".")>=0&&(m=g.split("."),g=m.shift(),m.sort()),l=0>g.indexOf(":")&&"on"+g,n=n[x.expando]?n:new x.Event(g,"object"==typeof n&&n),n.isTrigger=o?2:3,n.namespace=m.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+m.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,n.result=t,n.target||(n.target=i),r=null==r?[n]:x.makeArray(r,[n]),p=x.event.special[g]||{},o||!p.trigger||p.trigger.apply(i,r)!==!1)){if(!o&&!p.noBubble&&!x.isWindow(i)){for(c=p.delegateType||g,nt.test(c+g)||(u=u.parentNode);u;u=u.parentNode)h.push(u),f=u;f===(i.ownerDocument||a)&&h.push(f.defaultView||f.parentWindow||e)}d=0;while((u=h[d++])&&!n.isPropagationStopped())n.type=d>1?c:p.bindType||g,s=(x._data(u,"events")||{})[n.type]&&x._data(u,"handle"),s&&s.apply(u,r),s=l&&u[l],s&&x.acceptData(u)&&s.apply&&s.apply(u,r)===!1&&n.preventDefault();if(n.type=g,!o&&!n.isDefaultPrevented()&&(!p._default||p._default.apply(h.pop(),r)===!1)&&x.acceptData(i)&&l&&i[g]&&!x.isWindow(i)){f=i[l],f&&(i[l]=null),x.event.triggered=g;try{i[g]()}catch(y){}x.event.triggered=t,f&&(i[l]=f)}return n.result}},dispatch:function(e){e=x.event.fix(e);var n,r,i,o,a,s=[],l=g.call(arguments),u=(x._data(this,"events")||{})[e.type]||[],c=x.event.special[e.type]||{};if(l[0]=e,e.delegateTarget=this,!c.preDispatch||c.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),n=0;while((o=s[n++])&&!e.isPropagationStopped()){e.currentTarget=o.elem,a=0;while((i=o.handlers[a++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(i.namespace))&&(e.handleObj=i,e.data=i.data,r=((x.event.special[i.origType]||{}).handle||i.handler).apply(o.elem,l),r!==t&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,e),e.result}},handlers:function(e,n){var r,i,o,a,s=[],l=n.delegateCount,u=e.target;if(l&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(o=[],a=0;l>a;a++)i=n[a],r=i.selector+" ",o[r]===t&&(o[r]=i.needsContext?x(r,this).index(u)>=0:x.find(r,this,null,[u]).length),o[r]&&o.push(i);o.length&&s.push({elem:u,handlers:o})}return n.length>l&&s.push({elem:this,handlers:n.slice(l)}),s},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=tt.test(i)?this.mouseHooks:et.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return e.target||(e.target=o.srcElement||a),3===e.target.nodeType&&(e.target=e.target.parentNode),e.metaKey=!!e.metaKey,s.filter?s.filter(e,o):e},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,n){var r,i,o,s=n.button,l=n.fromElement;return null==e.pageX&&null!=n.clientX&&(i=e.target.ownerDocument||a,o=i.documentElement,r=i.body,e.pageX=n.clientX+(o&&o.scrollLeft||r&&r.scrollLeft||0)-(o&&o.clientLeft||r&&r.clientLeft||0),e.pageY=n.clientY+(o&&o.scrollTop||r&&r.scrollTop||0)-(o&&o.clientTop||r&&r.clientTop||0)),!e.relatedTarget&&l&&(e.relatedTarget=l===e.target?n.toElement:l),e.which||s===t||(e.which=1&s?1:2&s?3:4&s?2:0),e}},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==at()&&this.focus)try{return this.focus(),!1}catch(e){}},delegateType:"focusin"},blur:{trigger:function(){return this===at()&&this.blur?(this.blur(),!1):t},delegateType:"focusout"},click:{trigger:function(){return x.nodeName(this,"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):t},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==t&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=a.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){var r="on"+t;e.detachEvent&&(typeof e[r]===i&&(e[r]=null),e.detachEvent(r,n))},x.Event=function(e,n){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?it:ot):this.type=e,n&&x.extend(this,n),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,t):new x.Event(e,n)},x.Event.prototype={isDefaultPrevented:ot,isPropagationStopped:ot,isImmediatePropagationStopped:ot,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=it,e&&(e.preventDefault?e.preventDefault():e.returnValue=!1)},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=it,e&&(e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=it,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.submitBubbles||(x.event.special.submit={setup:function(){return x.nodeName(this,"form")?!1:(x.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=x.nodeName(n,"input")||x.nodeName(n,"button")?n.form:t;r&&!x._data(r,"submitBubbles")&&(x.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),x._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&x.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return x.nodeName(this,"form")?!1:(x.event.remove(this,"._submit"),t)}}),x.support.changeBubbles||(x.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(x.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),x.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),x.event.simulate("change",this,e,!0)})),!1):(x.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!x._data(t,"changeBubbles")&&(x.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||x.event.simulate("change",this.parentNode,e,!0)}),x._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return x.event.remove(this,"._change"),!Z.test(this.nodeName)}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&a.addEventListener(e,r,!0)},teardown:function(){0===--n&&a.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return x().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=x.guid++)),this.each(function(){x.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,x(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){x.event.remove(this,e,r,n)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?x.event.trigger(e,n,r,!0):t}});var st=/^.[^:#\[\.,]*$/,lt=/^(?:parents|prev(?:Until|All))/,ut=x.expr.match.needsContext,ct={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t,n=x(e,this),r=n.length;return this.filter(function(){for(t=0;r>t;t++)if(x.contains(this,n[t]))return!0})},not:function(e){return this.pushStack(ft(this,e||[],!0))},filter:function(e){return this.pushStack(ft(this,e||[],!1))},is:function(e){return!!ft(this,"string"==typeof e&&ut.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],a=ut.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(a?a.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?x.inArray(this[0],x(e)):x.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function pt(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return pt(e,"nextSibling")},prev:function(e){return pt(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(ct[e]||(i=x.unique(i)),lt.test(e)&&(i=i.reverse())),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,n,r){var i=[],o=e[n];while(o&&9!==o.nodeType&&(r===t||1!==o.nodeType||!x(o).is(r)))1===o.nodeType&&i.push(o),o=o[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function ft(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(st.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return x.inArray(e,t)>=0!==n})}function dt(e){var t=ht.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}var ht="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",gt=/ jQuery\d+="(?:null|\d+)"/g,mt=RegExp("<(?:"+ht+")[\\s/>]","i"),yt=/^\s+/,vt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bt=/<([\w:]+)/,xt=/<tbody/i,wt=/<|&#?\w+;/,Tt=/<(?:script|style|link)/i,Ct=/^(?:checkbox|radio)$/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,kt=/^$|\/(?:java|ecma)script/i,Et=/^true\/(.*)/,St=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,At={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],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>"],_default:x.support.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},jt=dt(a),Dt=jt.appendChild(a.createElement("div"));At.optgroup=At.option,At.tbody=At.tfoot=At.colgroup=At.caption=At.thead,At.th=At.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===t?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||a).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Lt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(Ft(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&_t(Ft(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++){1===e.nodeType&&x.cleanData(Ft(e,!1));while(e.firstChild)e.removeChild(e.firstChild);e.options&&x.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return 1===n.nodeType?n.innerHTML.replace(gt,""):t;if(!("string"!=typeof e||Tt.test(e)||!x.support.htmlSerialize&&mt.test(e)||!x.support.leadingWhitespace&&yt.test(e)||At[(bt.exec(e)||["",""])[1].toLowerCase()])){e=e.replace(vt,"<$1></$2>");try{for(;i>r;r++)n=this[r]||{},1===n.nodeType&&(x.cleanData(Ft(n,!1)),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=d.apply([],e);var r,i,o,a,s,l,u=0,c=this.length,p=this,f=c-1,h=e[0],g=x.isFunction(h);if(g||!(1>=c||"string"!=typeof h||x.support.checkClone)&&Nt.test(h))return this.each(function(r){var i=p.eq(r);g&&(e[0]=h.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(l=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),r=l.firstChild,1===l.childNodes.length&&(l=r),r)){for(a=x.map(Ft(l,"script"),Ht),o=a.length;c>u;u++)i=l,u!==f&&(i=x.clone(i,!0,!0),o&&x.merge(a,Ft(i,"script"))),t.call(this[u],i,u);if(o)for(s=a[a.length-1].ownerDocument,x.map(a,qt),u=0;o>u;u++)i=a[u],kt.test(i.type||"")&&!x._data(i,"globalEval")&&x.contains(s,i)&&(i.src?x._evalUrl(i.src):x.globalEval((i.text||i.textContent||i.innerHTML||"").replace(St,"")));l=r=null}return this}});function Lt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function Ht(e){return e.type=(null!==x.find.attr(e,"type"))+"/"+e.type,e}function qt(e){var t=Et.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function _t(e,t){var n,r=0;for(;null!=(n=e[r]);r++)x._data(n,"globalEval",!t||x._data(t[r],"globalEval"))}function Mt(e,t){if(1===t.nodeType&&x.hasData(e)){var n,r,i,o=x._data(e),a=x._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;i>r;r++)x.event.add(t,n,s[n][r])}a.data&&(a.data=x.extend({},a.data))}}function Ot(e,t){var n,r,i;if(1===t.nodeType){if(n=t.nodeName.toLowerCase(),!x.support.noCloneEvent&&t[x.expando]){i=x._data(t);for(r in i.events)x.removeEvent(t,r,i.handle);t.removeAttribute(x.expando)}"script"===n&&t.text!==e.text?(Ht(t).text=e.text,qt(t)):"object"===n?(t.parentNode&&(t.outerHTML=e.outerHTML),x.support.html5Clone&&e.innerHTML&&!x.trim(t.innerHTML)&&(t.innerHTML=e.innerHTML)):"input"===n&&Ct.test(e.type)?(t.defaultChecked=t.checked=e.checked,t.value!==e.value&&(t.value=e.value)):"option"===n?t.defaultSelected=t.selected=e.defaultSelected:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}}x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=0,i=[],o=x(e),a=o.length-1;for(;a>=r;r++)n=r===a?this:this.clone(!0),x(o[r])[t](n),h.apply(i,n.get());return this.pushStack(i)}});function Ft(e,n){var r,o,a=0,s=typeof e.getElementsByTagName!==i?e.getElementsByTagName(n||"*"):typeof e.querySelectorAll!==i?e.querySelectorAll(n||"*"):t;if(!s)for(s=[],r=e.childNodes||e;null!=(o=r[a]);a++)!n||x.nodeName(o,n)?s.push(o):x.merge(s,Ft(o,n));return n===t||n&&x.nodeName(e,n)?x.merge([e],s):s}function Bt(e){Ct.test(e.type)&&(e.defaultChecked=e.checked)}x.extend({clone:function(e,t,n){var r,i,o,a,s,l=x.contains(e.ownerDocument,e);if(x.support.html5Clone||x.isXMLDoc(e)||!mt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(Dt.innerHTML=e.outerHTML,Dt.removeChild(o=Dt.firstChild)),!(x.support.noCloneEvent&&x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(r=Ft(o),s=Ft(e),a=0;null!=(i=s[a]);++a)r[a]&&Ot(i,r[a]);if(t)if(n)for(s=s||Ft(e),r=r||Ft(o),a=0;null!=(i=s[a]);a++)Mt(i,r[a]);else Mt(e,o);return r=Ft(o,"script"),r.length>0&&_t(r,!l&&Ft(e,"script")),r=s=i=null,o},buildFragment:function(e,t,n,r){var i,o,a,s,l,u,c,p=e.length,f=dt(t),d=[],h=0;for(;p>h;h++)if(o=e[h],o||0===o)if("object"===x.type(o))x.merge(d,o.nodeType?[o]:o);else if(wt.test(o)){s=s||f.appendChild(t.createElement("div")),l=(bt.exec(o)||["",""])[1].toLowerCase(),c=At[l]||At._default,s.innerHTML=c[1]+o.replace(vt,"<$1></$2>")+c[2],i=c[0];while(i--)s=s.lastChild;if(!x.support.leadingWhitespace&&yt.test(o)&&d.push(t.createTextNode(yt.exec(o)[0])),!x.support.tbody){o="table"!==l||xt.test(o)?"<table>"!==c[1]||xt.test(o)?0:s:s.firstChild,i=o&&o.childNodes.length;while(i--)x.nodeName(u=o.childNodes[i],"tbody")&&!u.childNodes.length&&o.removeChild(u)}x.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),x.support.appendChecked||x.grep(Ft(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===x.inArray(o,r))&&(a=x.contains(o.ownerDocument,o),s=Ft(f.appendChild(o),"script"),a&&_t(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,l=x.expando,u=x.cache,c=x.support.deleteExpando,f=x.event.special;for(;null!=(n=e[s]);s++)if((t||x.acceptData(n))&&(o=n[l],a=o&&u[o])){if(a.events)for(r in a.events)f[r]?x.event.remove(n,r):x.removeEvent(n,r,a.handle);
u[o]&&(delete u[o],c?delete n[l]:typeof n.removeAttribute!==i?n.removeAttribute(l):n[l]=null,p.push(o))}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}}),x.fn.extend({wrapAll:function(e){if(x.isFunction(e))return this.each(function(t){x(this).wrapAll(e.call(this,t))});if(this[0]){var t=x(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&1===e.firstChild.nodeType)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+w+")(.*)$","i"),Yt=RegExp("^("+w+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+w+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=x._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=x._data(r,"olddisplay",ln(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&x._data(r,"olddisplay",i?n:x.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}x.fn.extend({css:function(e,n){return x.access(this,function(e,n,r){var i,o,a={},s=0;if(x.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=x.css(e,n[s],!1,o);return a}return r!==t?x.style(e,n,r):x.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){nn(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":x.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,l=x.camelCase(n),u=e.style;if(n=x.cssProps[l]||(x.cssProps[l]=tn(u,l)),s=x.cssHooks[n]||x.cssHooks[l],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:u[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(x.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||x.cssNumber[l]||(r+="px"),x.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(u[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{u[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,l=x.camelCase(n);return n=x.cssProps[l]||(x.cssProps[l]=tn(e.style,l)),s=x.cssHooks[n]||x.cssHooks[l],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||x.isNumeric(o)?o||0:a):a}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s.getPropertyValue(n)||s[n]:t,u=e.style;return s&&(""!==l||x.contains(e.ownerDocument,e)||(l=x.style(e,n)),Yt.test(l)&&Ut.test(n)&&(i=u.width,o=u.minWidth,a=u.maxWidth,u.minWidth=u.maxWidth=u.width=l,l=s.width,u.width=i,u.minWidth=o,u.maxWidth=a)),l}):a.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),l=s?s[n]:t,u=e.style;return null==l&&u&&u[n]&&(l=u[n]),Yt.test(l)&&!zt.test(n)&&(i=u.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),u.left="fontSize"===n?"1em":l,l=u.pixelLeft+"px",u.left=i,a&&(o.left=a)),""===l?"auto":l});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=x.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=x.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=x.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=x.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=x.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+an(e,t,n||(a?"border":"content"),r,o)+"px"}function ln(e){var t=a,n=Gt[e];return n||(n=un(e,t),"none"!==n&&n||(Pt=(Pt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(Pt[0].contentWindow||Pt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=un(e,t),Pt.detach()),Gt[e]=n),n}function un(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,n){x.cssHooks[n]={get:function(e,r,i){return r?0===e.offsetWidth&&Xt.test(x.css(e,"display"))?x.swap(e,Qt,function(){return sn(e,n,i)}):sn(e,n,i):t},set:function(e,t,r){var i=r&&Rt(e);return on(e,t,r?an(e,n,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x.support.opacity||(x.cssHooks.opacity={get:function(e,t){return It.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=x.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===x.trim(o.replace($t,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=$t.test(o)?o.replace($t,i):o+" "+i)}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,n){return n?x.swap(e,{display:"inline-block"},Wt,[e,"marginRight"]):t}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,n){x.cssHooks[n]={get:function(e,r){return r?(r=Wt(e,n),Yt.test(r)?x(e).position()[n]+"px":r):t}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight||!x.support.reliableHiddenOffsets&&"none"===(e.style&&e.style.display||x.css(e,"display"))},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+Zt[r]+t]=o[r]||o[r-2]||o[0];return i}},Ut.test(e)||(x.cssHooks[e+t].set=on)});var cn=/%20/g,pn=/\[\]$/,fn=/\r?\n/g,dn=/^(?:submit|button|image|reset|file)$/i,hn=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&hn.test(this.nodeName)&&!dn.test(e)&&(this.checked||!Ct.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(fn,"\r\n")}}):{name:t.name,value:n.replace(fn,"\r\n")}}).get()}}),x.param=function(e,n){var r,i=[],o=function(e,t){t=x.isFunction(t)?t():null==t?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(n===t&&(n=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){o(this.name,this.value)});else for(r in e)gn(r,e[r],n,o);return i.join("&").replace(cn,"+")};function gn(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||pn.test(e)?r(e,i):gn(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)gn(e+"["+i+"]",t[i],n,r)}x.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(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var mn,yn,vn=x.now(),bn=/\?/,xn=/#.*$/,wn=/([?&])_=[^&]*/,Tn=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Cn=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Nn=/^(?:GET|HEAD)$/,kn=/^\/\//,En=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,Sn=x.fn.load,An={},jn={},Dn="*/".concat("*");try{yn=o.href}catch(Ln){yn=a.createElement("a"),yn.href="",yn=yn.href}mn=En.exec(yn.toLowerCase())||[];function Hn(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(T)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function qn(e,n,r,i){var o={},a=e===jn;function s(l){var u;return o[l]=!0,x.each(e[l]||[],function(e,l){var c=l(n,r,i);return"string"!=typeof c||a||o[c]?a?!(u=c):t:(n.dataTypes.unshift(c),s(c),!1)}),u}return s(n.dataTypes[0])||!o["*"]&&s("*")}function _n(e,n){var r,i,o=x.ajaxSettings.flatOptions||{};for(i in n)n[i]!==t&&((o[i]?e:r||(r={}))[i]=n[i]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,n,r){if("string"!=typeof e&&Sn)return Sn.apply(this,arguments);var i,o,a,s=this,l=e.indexOf(" ");return l>=0&&(i=e.slice(l,e.length),e=e.slice(0,l)),x.isFunction(n)?(r=n,n=t):n&&"object"==typeof n&&(a="POST"),s.length>0&&x.ajax({url:e,type:a,dataType:"html",data:n}).done(function(e){o=arguments,s.html(i?x("<div>").append(x.parseHTML(e)).find(i):e)}).complete(r&&function(e,t){s.each(r,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:yn,type:"GET",isLocal:Cn.test(mn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Dn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?_n(_n(e,x.ajaxSettings),t):_n(x.ajaxSettings,e)},ajaxPrefilter:Hn(An),ajaxTransport:Hn(jn),ajax:function(e,n){"object"==typeof e&&(n=e,e=t),n=n||{};var r,i,o,a,s,l,u,c,p=x.ajaxSetup({},n),f=p.context||p,d=p.context&&(f.nodeType||f.jquery)?x(f):x.event,h=x.Deferred(),g=x.Callbacks("once memory"),m=p.statusCode||{},y={},v={},b=0,w="canceled",C={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!c){c={};while(t=Tn.exec(a))c[t[1].toLowerCase()]=t[2]}t=c[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?a:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=v[n]=v[n]||e,y[e]=t),this},overrideMimeType:function(e){return b||(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>b)for(t in e)m[t]=[m[t],e[t]];else C.always(e[C.status]);return this},abort:function(e){var t=e||w;return u&&u.abort(t),k(0,t),this}};if(h.promise(C).complete=g.add,C.success=C.done,C.error=C.fail,p.url=((e||p.url||yn)+"").replace(xn,"").replace(kn,mn[1]+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=x.trim(p.dataType||"*").toLowerCase().match(T)||[""],null==p.crossDomain&&(r=En.exec(p.url.toLowerCase()),p.crossDomain=!(!r||r[1]===mn[1]&&r[2]===mn[2]&&(r[3]||("http:"===r[1]?"80":"443"))===(mn[3]||("http:"===mn[1]?"80":"443")))),p.data&&p.processData&&"string"!=typeof p.data&&(p.data=x.param(p.data,p.traditional)),qn(An,p,n,C),2===b)return C;l=p.global,l&&0===x.active++&&x.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Nn.test(p.type),o=p.url,p.hasContent||(p.data&&(o=p.url+=(bn.test(o)?"&":"?")+p.data,delete p.data),p.cache===!1&&(p.url=wn.test(o)?o.replace(wn,"$1_="+vn++):o+(bn.test(o)?"&":"?")+"_="+vn++)),p.ifModified&&(x.lastModified[o]&&C.setRequestHeader("If-Modified-Since",x.lastModified[o]),x.etag[o]&&C.setRequestHeader("If-None-Match",x.etag[o])),(p.data&&p.hasContent&&p.contentType!==!1||n.contentType)&&C.setRequestHeader("Content-Type",p.contentType),C.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+Dn+"; q=0.01":""):p.accepts["*"]);for(i in p.headers)C.setRequestHeader(i,p.headers[i]);if(p.beforeSend&&(p.beforeSend.call(f,C,p)===!1||2===b))return C.abort();w="abort";for(i in{success:1,error:1,complete:1})C[i](p[i]);if(u=qn(jn,p,n,C)){C.readyState=1,l&&d.trigger("ajaxSend",[C,p]),p.async&&p.timeout>0&&(s=setTimeout(function(){C.abort("timeout")},p.timeout));try{b=1,u.send(y,k)}catch(N){if(!(2>b))throw N;k(-1,N)}}else k(-1,"No Transport");function k(e,n,r,i){var c,y,v,w,T,N=n;2!==b&&(b=2,s&&clearTimeout(s),u=t,a=i||"",C.readyState=e>0?4:0,c=e>=200&&300>e||304===e,r&&(w=Mn(p,C,r)),w=On(p,w,C,c),c?(p.ifModified&&(T=C.getResponseHeader("Last-Modified"),T&&(x.lastModified[o]=T),T=C.getResponseHeader("etag"),T&&(x.etag[o]=T)),204===e||"HEAD"===p.type?N="nocontent":304===e?N="notmodified":(N=w.state,y=w.data,v=w.error,c=!v)):(v=N,(e||!N)&&(N="error",0>e&&(e=0))),C.status=e,C.statusText=(n||N)+"",c?h.resolveWith(f,[y,N,C]):h.rejectWith(f,[C,N,v]),C.statusCode(m),m=t,l&&d.trigger(c?"ajaxSuccess":"ajaxError",[C,p,c?y:v]),g.fireWith(f,[C,N]),l&&(d.trigger("ajaxComplete",[C,p]),--x.active||x.event.trigger("ajaxStop")))}return C},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,n){return x.get(e,t,n,"script")}}),x.each(["get","post"],function(e,n){x[n]=function(e,r,i,o){return x.isFunction(r)&&(o=o||i,i=r,r=t),x.ajax({url:e,type:n,dataType:o,data:r,success:i})}});function Mn(e,n,r){var i,o,a,s,l=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),o===t&&(o=e.mimeType||n.getResponseHeader("Content-Type"));if(o)for(s in l)if(l[s]&&l[s].test(o)){u.unshift(s);break}if(u[0]in r)a=u[0];else{for(s in r){if(!u[0]||e.converters[s+" "+u[0]]){a=s;break}i||(i=s)}a=a||i}return a?(a!==u[0]&&u.unshift(a),r[a]):t}function On(e,t,n,r){var i,o,a,s,l,u={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)u[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!l&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),l=o,o=c.shift())if("*"===o)o=l;else if("*"!==l&&l!==o){if(a=u[l+" "+o]||u["* "+o],!a)for(i in u)if(s=i.split(" "),s[1]===o&&(a=u[l+" "+s[0]]||u["* "+s[0]])){a===!0?a=u[i]:u[i]!==!0&&(o=s[0],c.unshift(s[1]));break}if(a!==!0)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(p){return{state:"parsererror",error:a?p:"No conversion from "+l+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),x.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=a.head||x("head")[0]||a.documentElement;return{send:function(t,i){n=a.createElement("script"),n.async=!0,e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,t){(t||!n.readyState||/loaded|complete/.test(n.readyState))&&(n.onload=n.onreadystatechange=null,n.parentNode&&n.parentNode.removeChild(n),n=null,t||i(200,"success"))},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(t,!0)}}}});var Fn=[],Bn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Fn.pop()||x.expando+"_"+vn++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(n,r,i){var o,a,s,l=n.jsonp!==!1&&(Bn.test(n.url)?"url":"string"==typeof n.data&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Bn.test(n.data)&&"data");return l||"jsonp"===n.dataTypes[0]?(o=n.jsonpCallback=x.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,l?n[l]=n[l].replace(Bn,"$1"+o):n.jsonp!==!1&&(n.url+=(bn.test(n.url)?"&":"?")+n.jsonp+"="+o),n.converters["script json"]=function(){return s||x.error(o+" was not called"),s[0]},n.dataTypes[0]="json",a=e[o],e[o]=function(){s=arguments},i.always(function(){e[o]=a,n[o]&&(n.jsonpCallback=r.jsonpCallback,Fn.push(o)),s&&x.isFunction(a)&&a(s[0]),s=a=t}),"script"):t});var Pn,Rn,Wn=0,$n=e.ActiveXObject&&function(){var e;for(e in Pn)Pn[e](t,!0)};function In(){try{return new e.XMLHttpRequest}catch(t){}}function zn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}x.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&In()||zn()}:In,Rn=x.ajaxSettings.xhr(),x.support.cors=!!Rn&&"withCredentials"in Rn,Rn=x.support.ajax=!!Rn,Rn&&x.ajaxTransport(function(n){if(!n.crossDomain||x.support.cors){var r;return{send:function(i,o){var a,s,l=n.xhr();if(n.username?l.open(n.type,n.url,n.async,n.username,n.password):l.open(n.type,n.url,n.async),n.xhrFields)for(s in n.xhrFields)l[s]=n.xhrFields[s];n.mimeType&&l.overrideMimeType&&l.overrideMimeType(n.mimeType),n.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");try{for(s in i)l.setRequestHeader(s,i[s])}catch(u){}l.send(n.hasContent&&n.data||null),r=function(e,i){var s,u,c,p;try{if(r&&(i||4===l.readyState))if(r=t,a&&(l.onreadystatechange=x.noop,$n&&delete Pn[a]),i)4!==l.readyState&&l.abort();else{p={},s=l.status,u=l.getAllResponseHeaders(),"string"==typeof l.responseText&&(p.text=l.responseText);try{c=l.statusText}catch(f){c=""}s||!n.isLocal||n.crossDomain?1223===s&&(s=204):s=p.text?200:404}}catch(d){i||o(-1,d)}p&&o(s,c,p,u)},n.async?4===l.readyState?setTimeout(r):(a=++Wn,$n&&(Pn||(Pn={},x(e).unload($n)),Pn[a]=r),l.onreadystatechange=r):r()},abort:function(){r&&r(t,!0)}}}});var Xn,Un,Vn=/^(?:toggle|show|hide)$/,Yn=RegExp("^(?:([+-])=|)("+w+")([a-z%]*)$","i"),Jn=/queueHooks$/,Gn=[nr],Qn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Yn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),a=(x.cssNumber[e]||"px"!==o&&+r)&&Yn.exec(x.css(n.elem,e)),s=1,l=20;if(a&&a[3]!==o){o=o||a[3],i=i||[],a=+r||1;do s=s||".5",a/=s,x.style(n.elem,e,a+o);while(s!==(s=n.cur()/r)&&1!==s&&--l)}return i&&(a=n.start=+a||+r||0,n.unit=o,n.end=i[1]?a+(i[1]+1)*i[2]:+i[2]),n}]};function Kn(){return setTimeout(function(){Xn=t}),Xn=x.now()}function Zn(e,t,n){var r,i=(Qn[t]||[]).concat(Qn["*"]),o=0,a=i.length;for(;a>o;o++)if(r=i[o].call(n,t,e))return r}function er(e,t,n){var r,i,o=0,a=Gn.length,s=x.Deferred().always(function(){delete l.elem}),l=function(){if(i)return!1;var t=Xn||Kn(),n=Math.max(0,u.startTime+u.duration-t),r=n/u.duration||0,o=1-r,a=0,l=u.tweens.length;for(;l>a;a++)u.tweens[a].run(o);return s.notifyWith(e,[u,o,n]),1>o&&l?n:(s.resolveWith(e,[u]),!1)},u=s.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:Xn||Kn(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,u.opts,t,n,u.opts.specialEasing[t]||u.opts.easing);return u.tweens.push(r),r},stop:function(t){var n=0,r=t?u.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)u.tweens[n].run(1);return t?s.resolveWith(e,[u,t]):s.rejectWith(e,[u,t]),this}}),c=u.props;for(tr(c,u.opts.specialEasing);a>o;o++)if(r=Gn[o].call(u,e,c,u.opts))return r;return x.map(c,Zn,u),x.isFunction(u.opts.start)&&u.opts.start.call(e,u),x.fx.timer(x.extend(l,{elem:e,anim:u,queue:u.opts.queue})),u.progress(u.opts.progress).done(u.opts.done,u.opts.complete).fail(u.opts.fail).always(u.opts.always)}function tr(e,t){var n,r,i,o,a;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),a=x.cssHooks[r],a&&"expand"in a){o=a.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(er,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Qn[n]=Qn[n]||[],Qn[n].unshift(t)},prefilter:function(e,t){t?Gn.unshift(e):Gn.push(e)}});function nr(e,t,n){var r,i,o,a,s,l,u=this,c={},p=e.style,f=e.nodeType&&nn(e),d=x._data(e,"fxshow");n.queue||(s=x._queueHooks(e,"fx"),null==s.unqueued&&(s.unqueued=0,l=s.empty.fire,s.empty.fire=function(){s.unqueued||l()}),s.unqueued++,u.always(function(){u.always(function(){s.unqueued--,x.queue(e,"fx").length||s.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(x.support.inlineBlockNeedsLayout&&"inline"!==ln(e.nodeName)?p.zoom=1:p.display="inline-block")),n.overflow&&(p.overflow="hidden",x.support.shrinkWrapBlocks||u.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],Vn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show"))continue;c[r]=d&&d[r]||x.style(e,r)}if(!x.isEmptyObject(c)){d?"hidden"in d&&(f=d.hidden):d=x._data(e,"fxshow",{}),o&&(d.hidden=!f),f?x(e).show():u.done(function(){x(e).hide()}),u.done(function(){var t;x._removeData(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)a=Zn(f?d[r]:0,r,u),r in d||(d[r]=a.start,f&&(a.end=a.start,a.start="width"===r||"height"===r?1:0))}}function rr(e,t,n,r,i){return new rr.prototype.init(e,t,n,r,i)}x.Tween=rr,rr.prototype={constructor:rr,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=rr.propHooks[this.prop];return e&&e.get?e.get(this):rr.propHooks._default.get(this)},run:function(e){var t,n=rr.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):rr.propHooks._default.set(this),this}},rr.prototype.init.prototype=rr.prototype,rr.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},rr.propHooks.scrollTop=rr.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(ir(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(nn).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),a=function(){var t=er(this,x.extend({},e),o);(i||x._data(this,"finish"))&&t.stop(!0)};return a.finish=a,i||o.queue===!1?this.each(a):this.queue(o.queue,a)},stop:function(e,n,r){var i=function(e){var t=e.stop;delete e.stop,t(r)};return"string"!=typeof e&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,n=null!=e&&e+"queueHooks",o=x.timers,a=x._data(this);if(n)a[n]&&a[n].stop&&i(a[n]);else for(n in a)a[n]&&a[n].stop&&Jn.test(n)&&i(a[n]);for(n=o.length;n--;)o[n].elem!==this||null!=e&&o[n].queue!==e||(o[n].anim.stop(r),t=!1,o.splice(n,1));(t||!r)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=x._data(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,a=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;a>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function ir(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=Zt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:ir("show"),slideUp:ir("hide"),slideToggle:ir("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=rr.prototype.init,x.fx.tick=function(){var e,n=x.timers,r=0;for(Xn=x.now();n.length>r;r++)e=n[r],e()||n[r]!==e||n.splice(r--,1);n.length||x.fx.stop(),Xn=t},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){Un||(Un=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(Un),Un=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){x.offset.setOffset(this,e,t)});var n,r,o={top:0,left:0},a=this[0],s=a&&a.ownerDocument;if(s)return n=s.documentElement,x.contains(n,a)?(typeof a.getBoundingClientRect!==i&&(o=a.getBoundingClientRect()),r=or(s),{top:o.top+(r.pageYOffset||n.scrollTop)-(n.clientTop||0),left:o.left+(r.pageXOffset||n.scrollLeft)-(n.clientLeft||0)}):o},x.offset={setOffset:function(e,t,n){var r=x.css(e,"position");"static"===r&&(e.style.position="relative");var i=x(e),o=i.offset(),a=x.css(e,"top"),s=x.css(e,"left"),l=("absolute"===r||"fixed"===r)&&x.inArray("auto",[a,s])>-1,u={},c={},p,f;l?(c=i.position(),p=c.top,f=c.left):(p=parseFloat(a)||0,f=parseFloat(s)||0),x.isFunction(t)&&(t=t.call(e,n,o)),null!=t.top&&(u.top=t.top-o.top+p),null!=t.left&&(u.left=t.left-o.left+f),"using"in t?t.using.call(e,u):i.css(u)}},x.fn.extend({position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===x.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(n=e.offset()),n.top+=x.css(e[0],"borderTopWidth",!0),n.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-x.css(r,"marginTop",!0),left:t.left-n.left-x.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);x.fn[e]=function(i){return x.access(this,function(e,i,o){var a=or(e);return o===t?a?n in a?a[n]:a.document.documentElement[i]:e[i]:(a?a.scrollTo(r?x(a).scrollLeft():o,r?o:x(a).scrollTop()):e[i]=o,t)},e,i,arguments.length,null)}});function or(e){return x.isWindow(e)?e:9===e.nodeType?e.defaultView||e.parentWindow:!1}x.each({Height:"height",Width:"width"},function(e,n){x.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){x.fn[i]=function(i,o){var a=arguments.length&&(r||"boolean"!=typeof i),s=r||(i===!0||o===!0?"margin":"border");return x.access(this,function(n,r,i){var o;return x.isWindow(n)?n.document.documentElement["client"+e]:9===n.nodeType?(o=n.documentElement,Math.max(n.body["scroll"+e],o["scroll"+e],n.body["offset"+e],o["offset"+e],o["client"+e])):i===t?x.css(n,r,s):x.style(n,r,i,s)},n,a?i:t,a,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:(e.jQuery=e.$=x,"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}))})(window);
;
/* NUGET: BEGIN LICENSE TEXT
 *
 * Microsoft grants you the right to use these script files for the sole
 * purpose of either: (i) interacting through your browser with the Microsoft
 * website or online service, subject to the applicable licensing or use
 * terms; or (ii) using the files as included with a Microsoft product subject
 * to that product's license terms. Microsoft reserves all other rights to the
 * files not expressly granted by Microsoft, whether by implication, estoppel
 * or otherwise. Insofar as a script file is dual licensed under GPL,
 * Microsoft neither took the code under GPL nor distributes it thereunder but
 * under the terms set out in this paragraph. All notices and licenses
 * below are for informational purposes only.
 *
 * NUGET: END LICENSE TEXT */
/*! jQuery Validation Plugin - v1.11.1 - 3/22/2013\n* https://github.com/jzaefferer/jquery-validation
* Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */(function(t){t.extend(t.fn,{validate:function(e){if(!this.length)return e&&e.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."),void 0;var i=t.data(this[0],"validator");return i?i:(this.attr("novalidate","novalidate"),i=new t.validator(e,this[0]),t.data(this[0],"validator",i),i.settings.onsubmit&&(this.validateDelegate(":submit","click",function(e){i.settings.submitHandler&&(i.submitButton=e.target),t(e.target).hasClass("cancel")&&(i.cancelSubmit=!0),void 0!==t(e.target).attr("formnovalidate")&&(i.cancelSubmit=!0)}),this.submit(function(e){function s(){var s;return i.settings.submitHandler?(i.submitButton&&(s=t("<input type='hidden'/>").attr("name",i.submitButton.name).val(t(i.submitButton).val()).appendTo(i.currentForm)),i.settings.submitHandler.call(i,i.currentForm,e),i.submitButton&&s.remove(),!1):!0}return i.settings.debug&&e.preventDefault(),i.cancelSubmit?(i.cancelSubmit=!1,s()):i.form()?i.pendingRequest?(i.formSubmitted=!0,!1):s():(i.focusInvalid(),!1)})),i)},valid:function(){if(t(this[0]).is("form"))return this.validate().form();var e=!0,i=t(this[0].form).validate();return this.each(function(){e=e&&i.element(this)}),e},removeAttrs:function(e){var i={},s=this;return t.each(e.split(/\s/),function(t,e){i[e]=s.attr(e),s.removeAttr(e)}),i},rules:function(e,i){var s=this[0];if(e){var r=t.data(s.form,"validator").settings,n=r.rules,a=t.validator.staticRules(s);switch(e){case"add":t.extend(a,t.validator.normalizeRule(i)),delete a.messages,n[s.name]=a,i.messages&&(r.messages[s.name]=t.extend(r.messages[s.name],i.messages));break;case"remove":if(!i)return delete n[s.name],a;var u={};return t.each(i.split(/\s/),function(t,e){u[e]=a[e],delete a[e]}),u}}var o=t.validator.normalizeRules(t.extend({},t.validator.classRules(s),t.validator.attributeRules(s),t.validator.dataRules(s),t.validator.staticRules(s)),s);if(o.required){var l=o.required;delete o.required,o=t.extend({required:l},o)}return o}}),t.extend(t.expr[":"],{blank:function(e){return!t.trim(""+t(e).val())},filled:function(e){return!!t.trim(""+t(e).val())},unchecked:function(e){return!t(e).prop("checked")}}),t.validator=function(e,i){this.settings=t.extend(!0,{},t.validator.defaults,e),this.currentForm=i,this.init()},t.validator.format=function(e,i){return 1===arguments.length?function(){var i=t.makeArray(arguments);return i.unshift(e),t.validator.format.apply(this,i)}:(arguments.length>2&&i.constructor!==Array&&(i=t.makeArray(arguments).slice(1)),i.constructor!==Array&&(i=[i]),t.each(i,function(t,i){e=e.replace(RegExp("\\{"+t+"\\}","g"),function(){return i})}),e)},t.extend(t.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:t([]),errorLabelContainer:t([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(t){this.lastActive=t,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,t,this.settings.errorClass,this.settings.validClass),this.addWrapper(this.errorsFor(t)).hide())},onfocusout:function(t){this.checkable(t)||!(t.name in this.submitted)&&this.optional(t)||this.element(t)},onkeyup:function(t,e){(9!==e.which||""!==this.elementValue(t))&&(t.name in this.submitted||t===this.lastElement)&&this.element(t)},onclick:function(t){t.name in this.submitted?this.element(t):t.parentNode.name in this.submitted&&this.element(t.parentNode)},highlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).addClass(i).removeClass(s):t(e).addClass(i).removeClass(s)},unhighlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).removeClass(i).addClass(s):t(e).removeClass(i).addClass(s)}},setDefaults:function(e){t.extend(t.validator.defaults,e)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:t.validator.format("Please enter no more than {0} characters."),minlength:t.validator.format("Please enter at least {0} characters."),rangelength:t.validator.format("Please enter a value between {0} and {1} characters long."),range:t.validator.format("Please enter a value between {0} and {1}."),max:t.validator.format("Please enter a value less than or equal to {0}."),min:t.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function e(e){var i=t.data(this[0].form,"validator"),s="on"+e.type.replace(/^validate/,"");i.settings[s]&&i.settings[s].call(i,this[0],e)}this.labelContainer=t(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||t(this.currentForm),this.containers=t(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var i=this.groups={};t.each(this.settings.groups,function(e,s){"string"==typeof s&&(s=s.split(/\s/)),t.each(s,function(t,s){i[s]=e})});var s=this.settings.rules;t.each(s,function(e,i){s[e]=t.validator.normalizeRule(i)}),t(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",e).validateDelegate("[type='radio'], [type='checkbox'], select, option","click",e),this.settings.invalidHandler&&t(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),t.extend(this.submitted,this.errorMap),this.invalid=t.extend({},this.errorMap),this.valid()||t(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var t=0,e=this.currentElements=this.elements();e[t];t++)this.check(e[t]);return this.valid()},element:function(e){e=this.validationTargetFor(this.clean(e)),this.lastElement=e,this.prepareElement(e),this.currentElements=t(e);var i=this.check(e)!==!1;return i?delete this.invalid[e.name]:this.invalid[e.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),i},showErrors:function(e){if(e){t.extend(this.errorMap,e),this.errorList=[];for(var i in e)this.errorList.push({message:e[i],element:this.findByName(i)[0]});this.successList=t.grep(this.successList,function(t){return!(t.name in e)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){t.fn.resetForm&&t(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(t){var e=0;for(var i in t)e++;return e},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{t(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(e){}},findLastActive:function(){var e=this.lastActive;return e&&1===t.grep(this.errorList,function(t){return t.element.name===e.name}).length&&e},elements:function(){var e=this,i={};return t(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&e.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in i||!e.objectLength(t(this).rules())?!1:(i[this.name]=!0,!0)})},clean:function(e){return t(e)[0]},errors:function(){var e=this.settings.errorClass.replace(" ",".");return t(this.settings.errorElement+"."+e,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=t([]),this.toHide=t([]),this.currentElements=t([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(t){this.reset(),this.toHide=this.errorsFor(t)},elementValue:function(e){var i=t(e).attr("type"),s=t(e).val();return"radio"===i||"checkbox"===i?t("input[name='"+t(e).attr("name")+"']:checked").val():"string"==typeof s?s.replace(/\r/g,""):s},check:function(e){e=this.validationTargetFor(this.clean(e));var i,s=t(e).rules(),r=!1,n=this.elementValue(e);for(var a in s){var u={method:a,parameters:s[a]};try{if(i=t.validator.methods[a].call(this,n,e,u.parameters),"dependency-mismatch"===i){r=!0;continue}if(r=!1,"pending"===i)return this.toHide=this.toHide.not(this.errorsFor(e)),void 0;if(!i)return this.formatAndAdd(e,u),!1}catch(o){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+e.id+", check the '"+u.method+"' method.",o),o}}return r?void 0:(this.objectLength(s)&&this.successList.push(e),!0)},customDataMessage:function(e,i){return t(e).data("msg-"+i.toLowerCase())||e.attributes&&t(e).attr("data-msg-"+i.toLowerCase())},customMessage:function(t,e){var i=this.settings.messages[t];return i&&(i.constructor===String?i:i[e])},findDefined:function(){for(var t=0;arguments.length>t;t++)if(void 0!==arguments[t])return arguments[t];return void 0},defaultMessage:function(e,i){return this.findDefined(this.customMessage(e.name,i),this.customDataMessage(e,i),!this.settings.ignoreTitle&&e.title||void 0,t.validator.messages[i],"<strong>Warning: No message defined for "+e.name+"</strong>")},formatAndAdd:function(e,i){var s=this.defaultMessage(e,i.method),r=/\$?\{(\d+)\}/g;"function"==typeof s?s=s.call(this,i.parameters,e):r.test(s)&&(s=t.validator.format(s.replace(r,"{$1}"),i.parameters)),this.errorList.push({message:s,element:e}),this.errorMap[e.name]=s,this.submitted[e.name]=s},addWrapper:function(t){return this.settings.wrapper&&(t=t.add(t.parent(this.settings.wrapper))),t},defaultShowErrors:function(){var t,e;for(t=0;this.errorList[t];t++){var i=this.errorList[t];this.settings.highlight&&this.settings.highlight.call(this,i.element,this.settings.errorClass,this.settings.validClass),this.showLabel(i.element,i.message)}if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(t=0;this.successList[t];t++)this.showLabel(this.successList[t]);if(this.settings.unhighlight)for(t=0,e=this.validElements();e[t];t++)this.settings.unhighlight.call(this,e[t],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return t(this.errorList).map(function(){return this.element})},showLabel:function(e,i){var s=this.errorsFor(e);s.length?(s.removeClass(this.settings.validClass).addClass(this.settings.errorClass),s.html(i)):(s=t("<"+this.settings.errorElement+">").attr("for",this.idOrName(e)).addClass(this.settings.errorClass).html(i||""),this.settings.wrapper&&(s=s.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.append(s).length||(this.settings.errorPlacement?this.settings.errorPlacement(s,t(e)):s.insertAfter(e))),!i&&this.settings.success&&(s.text(""),"string"==typeof this.settings.success?s.addClass(this.settings.success):this.settings.success(s,e)),this.toShow=this.toShow.add(s)},errorsFor:function(e){var i=this.idOrName(e);return this.errors().filter(function(){return t(this).attr("for")===i})},idOrName:function(t){return this.groups[t.name]||(this.checkable(t)?t.name:t.id||t.name)},validationTargetFor:function(t){return this.checkable(t)&&(t=this.findByName(t.name).not(this.settings.ignore)[0]),t},checkable:function(t){return/radio|checkbox/i.test(t.type)},findByName:function(e){return t(this.currentForm).find("[name='"+e+"']")},getLength:function(e,i){switch(i.nodeName.toLowerCase()){case"select":return t("option:selected",i).length;case"input":if(this.checkable(i))return this.findByName(i.name).filter(":checked").length}return e.length},depend:function(t,e){return this.dependTypes[typeof t]?this.dependTypes[typeof t](t,e):!0},dependTypes:{"boolean":function(t){return t},string:function(e,i){return!!t(e,i.form).length},"function":function(t,e){return t(e)}},optional:function(e){var i=this.elementValue(e);return!t.validator.methods.required.call(this,i,e)&&"dependency-mismatch"},startRequest:function(t){this.pending[t.name]||(this.pendingRequest++,this.pending[t.name]=!0)},stopRequest:function(e,i){this.pendingRequest--,0>this.pendingRequest&&(this.pendingRequest=0),delete this.pending[e.name],i&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(t(this.currentForm).submit(),this.formSubmitted=!1):!i&&0===this.pendingRequest&&this.formSubmitted&&(t(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(e){return t.data(e,"previousValue")||t.data(e,"previousValue",{old:null,valid:!0,message:this.defaultMessage(e,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(e,i){e.constructor===String?this.classRuleSettings[e]=i:t.extend(this.classRuleSettings,e)},classRules:function(e){var i={},s=t(e).attr("class");return s&&t.each(s.split(" "),function(){this in t.validator.classRuleSettings&&t.extend(i,t.validator.classRuleSettings[this])}),i},attributeRules:function(e){var i={},s=t(e),r=s[0].getAttribute("type");for(var n in t.validator.methods){var a;"required"===n?(a=s.get(0).getAttribute(n),""===a&&(a=!0),a=!!a):a=s.attr(n),/min|max/.test(n)&&(null===r||/number|range|text/.test(r))&&(a=Number(a)),a?i[n]=a:r===n&&"range"!==r&&(i[n]=!0)}return i.maxlength&&/-1|2147483647|524288/.test(i.maxlength)&&delete i.maxlength,i},dataRules:function(e){var i,s,r={},n=t(e);for(i in t.validator.methods)s=n.data("rule-"+i.toLowerCase()),void 0!==s&&(r[i]=s);return r},staticRules:function(e){var i={},s=t.data(e.form,"validator");return s.settings.rules&&(i=t.validator.normalizeRule(s.settings.rules[e.name])||{}),i},normalizeRules:function(e,i){return t.each(e,function(s,r){if(r===!1)return delete e[s],void 0;if(r.param||r.depends){var n=!0;switch(typeof r.depends){case"string":n=!!t(r.depends,i.form).length;break;case"function":n=r.depends.call(i,i)}n?e[s]=void 0!==r.param?r.param:!0:delete e[s]}}),t.each(e,function(s,r){e[s]=t.isFunction(r)?r(i):r}),t.each(["minlength","maxlength"],function(){e[this]&&(e[this]=Number(e[this]))}),t.each(["rangelength","range"],function(){var i;e[this]&&(t.isArray(e[this])?e[this]=[Number(e[this][0]),Number(e[this][1])]:"string"==typeof e[this]&&(i=e[this].split(/[\s,]+/),e[this]=[Number(i[0]),Number(i[1])]))}),t.validator.autoCreateRanges&&(e.min&&e.max&&(e.range=[e.min,e.max],delete e.min,delete e.max),e.minlength&&e.maxlength&&(e.rangelength=[e.minlength,e.maxlength],delete e.minlength,delete e.maxlength)),e},normalizeRule:function(e){if("string"==typeof e){var i={};t.each(e.split(/\s/),function(){i[this]=!0}),e=i}return e},addMethod:function(e,i,s){t.validator.methods[e]=i,t.validator.messages[e]=void 0!==s?s:t.validator.messages[e],3>i.length&&t.validator.addClassRules(e,t.validator.normalizeRule(e))},methods:{required:function(e,i,s){if(!this.depend(s,i))return"dependency-mismatch";if("select"===i.nodeName.toLowerCase()){var r=t(i).val();return r&&r.length>0}return this.checkable(i)?this.getLength(e,i)>0:t.trim(e).length>0},email:function(t,e){return this.optional(e)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(t)},url:function(t,e){return this.optional(e)||/^(https?|s?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.test(t)},date:function(t,e){return this.optional(e)||!/Invalid|NaN/.test(""+new Date(t))},dateISO:function(t,e){return this.optional(e)||/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(t)},number:function(t,e){return this.optional(e)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(t)},digits:function(t,e){return this.optional(e)||/^\d+$/.test(t)},creditcard:function(t,e){if(this.optional(e))return"dependency-mismatch";if(/[^0-9 \-]+/.test(t))return!1;var i=0,s=0,r=!1;t=t.replace(/\D/g,"");for(var n=t.length-1;n>=0;n--){var a=t.charAt(n);s=parseInt(a,10),r&&(s*=2)>9&&(s-=9),i+=s,r=!r}return 0===i%10},minlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s},maxlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||s>=r},rangelength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s[0]&&s[1]>=r},min:function(t,e,i){return this.optional(e)||t>=i},max:function(t,e,i){return this.optional(e)||i>=t},range:function(t,e,i){return this.optional(e)||t>=i[0]&&i[1]>=t},equalTo:function(e,i,s){var r=t(s);return this.settings.onfocusout&&r.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){t(i).valid()}),e===r.val()},remote:function(e,i,s){if(this.optional(i))return"dependency-mismatch";var r=this.previousValue(i);if(this.settings.messages[i.name]||(this.settings.messages[i.name]={}),r.originalMessage=this.settings.messages[i.name].remote,this.settings.messages[i.name].remote=r.message,s="string"==typeof s&&{url:s}||s,r.old===e)return r.valid;r.old=e;var n=this;this.startRequest(i);var a={};return a[i.name]=e,t.ajax(t.extend(!0,{url:s,mode:"abort",port:"validate"+i.name,dataType:"json",data:a,success:function(s){n.settings.messages[i.name].remote=r.originalMessage;var a=s===!0||"true"===s;if(a){var u=n.formSubmitted;n.prepareElement(i),n.formSubmitted=u,n.successList.push(i),delete n.invalid[i.name],n.showErrors()}else{var o={},l=s||n.defaultMessage(i,"remote");o[i.name]=r.message=t.isFunction(l)?l(e):l,n.invalid[i.name]=!0,n.showErrors(o)}r.valid=a,n.stopRequest(i,a)}},s)),"pending"}}}),t.format=t.validator.format})(jQuery),function(t){var e={};if(t.ajaxPrefilter)t.ajaxPrefilter(function(t,i,s){var r=t.port;"abort"===t.mode&&(e[r]&&e[r].abort(),e[r]=s)});else{var i=t.ajax;t.ajax=function(s){var r=("mode"in s?s:t.ajaxSettings).mode,n=("port"in s?s:t.ajaxSettings).port;return"abort"===r?(e[n]&&e[n].abort(),e[n]=i.apply(this,arguments),e[n]):i.apply(this,arguments)}}}(jQuery),function(t){t.extend(t.fn,{validateDelegate:function(e,i,s){return this.bind(i,function(i){var r=t(i.target);return r.is(e)?s.apply(r,arguments):void 0})}})}(jQuery);;
/* NUGET: BEGIN LICENSE TEXT
*
* Microsoft grants you the right to use these script files for the sole
* purpose of either: (i) interacting through your browser with the Microsoft
* website or online service, subject to the applicable licensing or use
* terms; or (ii) using the files as included with a Microsoft product subject
* to that product's license terms. Microsoft reserves all other rights to the
* files not expressly granted by Microsoft, whether by implication, estoppel
* or otherwise. Insofar as a script file is dual licensed under GPL,
* Microsoft neither took the code under GPL nor distributes it thereunder but
* under the terms set out in this paragraph. All notices and licenses
* below are for informational purposes only.
*
* NUGET: END LICENSE TEXT */
/*
** Unobtrusive validation support library for jQuery and jQuery Validate
** Copyright (C) Microsoft Corporation. All rights reserved.
*/
(function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a("<li />").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this);b.data("validator").resetForm();b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(c){var b=a(c),d=b.data(e),f=a.proxy(n,c);if(!d){d={options:{errorClass:"input-validation-error",errorElement:"span",errorPlacement:a.proxy(m,c),invalidHandler:a.proxy(l,c),messages:{},rules:{},success:a.proxy(k,c)},attachValidation:function(){b.unbind("reset."+e,f).bind("reset."+e,f).validate(this.options)},validate:function(){b.validate();return b.valid()}};b.data(e,d)}return d}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(b){var c=a(b).parents("form").andSelf().add(a(b).find("form")).filter("form");a(b).find(":input").filter("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});c.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){return a(b.form).find(":input").filter("[name='"+f(c)+"']").val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery);
;
/**
 * @preserve jQuery DateTimePicker plugin v2.3.4
 * @homepage http://xdsoft.net/jqplugins/datetimepicker/
 * (c) 2014, Chupurnov Valeriy.
 */
(function( $ ) {
	'use strict';
	var default_options  = {
		i18n:{
			ar: { // Arabic
				months: [
					"كانون الثاني", "شباط", "آذار", "نيسان", "مايو", "حزيران", "تموز", "آب", "أيلول", "تشرين الأول", "تشرين الثاني", "كانون الأول"
				],
				dayOfWeek: [
					"ن", "ث", "ع", "خ", "ج", "س", "ح"
				]
			},
			ro: { // Romanian
				months: [
					"ianuarie", "februarie", "martie", "aprilie", "mai", "iunie", "iulie", "august", "septembrie", "octombrie", "noiembrie", "decembrie"
				],
				dayOfWeek: [
					"l", "ma", "mi", "j", "v", "s", "d"
				]
			},
			id: { // Indonesian
				months: [
					"Januari", "Februari", "Maret", "April", "Mei", "Juni", "Juli", "Agustus", "September", "Oktober", "November", "Desember"
				],
				dayOfWeek: [
					"Sen", "Sel", "Rab", "Kam", "Jum", "Sab", "Min"
				]
			},
			bg:{ // Bulgarian
				months:[
					"Януари", "Февруари", "Март", "Април", "Май", "Юни", "Юли", "Август", "Септември", "Октомври", "Ноември", "Декември"
				],
				dayOfWeek:[
					"Нд", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"
				]
			},
			fa:{ // Persian/Farsi
				months:[
					'فروردین', 'اردیبهشت', 'خرداد', 'تیر', 'مرداد', 'شهریور', 'مهر', 'آبان', 'آذر', 'دی', 'بهمن', 'اسفند'
				],
				dayOfWeek:[
					'یکشنبه', 'دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنجشنبه', 'جمعه', 'شنبه'
				]
			},
			ru:{ // Russian
				months:[
					'Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'
				],
				dayOfWeek:[
					"Вск", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"
				]
			},
			uk:{ // Ukrainian
				months:[
					'Січень','Лютий','Березень','Квітень','Травень','Червень','Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'
				],
				dayOfWeek:[
					"Ндл", "Пнд", "Втр", "Срд", "Чтв", "Птн", "Сбт"
				]
			},
			en:{ // English
				months: [
					"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
				],
				dayOfWeek: [
					"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
				]
			},
			el:{ // Ελληνικά
				months: [
					"Ιανουάριος", "Φεβρουάριος", "Μάρτιος", "Απρίλιος", "Μάιος", "Ιούνιος", "Ιούλιος", "Αύγουστος", "Σεπτέμβριος", "Οκτώβριος", "Νοέμβριος", "Δεκέμβριος"
				],
				dayOfWeek: [
					"Κυρ", "Δευ", "Τρι", "Τετ", "Πεμ", "Παρ", "Σαβ"
				]
			},
			de:{ // German
				months:[
					'Januar','Februar','März','April','Mai','Juni','Juli','August','September','Oktober','November','Dezember'
				],
				dayOfWeek:[
					"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"
				]
			},
			nl:{ // Dutch
				months:[
					"januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"
				],
				dayOfWeek:[
					"zo", "ma", "di", "wo", "do", "vr", "za"
				]
			},
			tr:{ // Turkish
				months:[
					"Ocak", "Şubat", "Mart", "Nisan", "Mayıs", "Haziran", "Temmuz", "Ağustos", "Eylül", "Ekim", "Kasım", "Aralık"
				],
				dayOfWeek:[
					"Paz", "Pts", "Sal", "Çar", "Per", "Cum", "Cts"
				]
			},
			fr:{ //French
				months:[
			    "Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"
				],
				dayOfWeek:[
					"Dim", "Lun", "Mar", "Mer", "Jeu", "Ven", "Sam"
				]
			},
			es:{ // Spanish
				months: [
					"Enero", "Febrero", "Marzo", "Abril", "Mayo", "Junio", "Julio", "Agosto", "Septiembre", "Octubre", "Noviembre", "Diciembre"
				],
				dayOfWeek: [
					"Dom", "Lun", "Mar", "Mié", "Jue", "Vie", "Sáb"
				]
			},
			th:{ // Thai
				months:[
					'มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน','กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'
				],
				dayOfWeek:[
					'อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'
				]
			},
			pl:{ // Polish
				months: [
					"styczeń", "luty", "marzec", "kwiecień", "maj", "czerwiec", "lipiec", "sierpień", "wrzesień", "październik", "listopad", "grudzień"
				],
				dayOfWeek: [
					"nd", "pn", "wt", "śr", "cz", "pt", "sb"
				]
			},
			pt:{ // Portuguese
				months: [
					"Janeiro", "Fevereiro", "Março", "Abril", "Maio", "Junho", "Julho", "Agosto", "Setembro", "Outubro", "Novembro", "Dezembro"
				],
				dayOfWeek: [
					"Dom", "Seg", "Ter", "Qua", "Qui", "Sex", "Sab"
				]
			},
			ch:{ // Simplified Chinese
				months: [
					"一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"
				],
				dayOfWeek: [
					"日", "一","二","三","四","五","六"
				]
			},
			se:{ // Swedish
				months: [
					"Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September","Oktober", "November", "December"
				],
				dayOfWeek: [
					"Sön", "Mån", "Tis", "Ons", "Tor", "Fre", "Lör"
				]
			},
			kr:{ // Korean
				months: [
					"1월", "2월", "3월", "4월", "5월", "6월", "7월", "8월", "9월", "10월", "11월", "12월"
				],
				dayOfWeek: [
					"일", "월", "화", "수", "목", "금", "토"
				]
			},
			it:{ // Italian
				months: [
					"Gennaio", "Febbraio", "Marzo", "Aprile", "Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre", "Novembre", "Dicembre"
				],
				dayOfWeek: [
					"Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"
				]
			},
			da:{ // Dansk
				months: [
					"January", "Februar", "Marts", "April", "Maj", "Juni", "July", "August", "September", "Oktober", "November", "December"
				],
				dayOfWeek: [
					"Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør"
				]
			},
			no:{ // Norwegian
				months: [
					"Januar", "Februar", "Mars", "April", "Mai", "Juni", "Juli", "August", "September", "Oktober", "November", "Desember"
				],
				dayOfWeek: [
					"Søn", "Man", "Tir", "Ons", "Tor", "Fre", "Lør"
				]
			},
			ja:{ // Japanese
				months: [
					"1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"
				],
				dayOfWeek: [
					"日", "月", "火", "水", "木", "金", "土"
				]
			},
			vi:{ // Vietnamese
				months: [
					"Tháng 1", "Tháng 2", "Tháng 3", "Tháng 4", "Tháng 5", "Tháng 6", "Tháng 7", "Tháng 8", "Tháng 9", "Tháng 10", "Tháng 11", "Tháng 12"
				],
				dayOfWeek: [
					"CN", "T2", "T3", "T4", "T5", "T6", "T7"
				]
			},
			sl:{ // Slovenščina
				months: [
					"Januar", "Februar", "Marec", "April", "Maj", "Junij", "Julij", "Avgust", "September", "Oktober", "November", "December"
				],
				dayOfWeek: [
					"Ned", "Pon", "Tor", "Sre", "Čet", "Pet", "Sob"
				]
			},
			cs:{ // Čeština
				months: [
					"Leden", "Únor", "Březen", "Duben", "Květen", "Červen", "Červenec", "Srpen", "Září", "Říjen", "Listopad", "Prosinec"
				],
				dayOfWeek: [
					"Ne", "Po", "Út", "St", "Čt", "Pá", "So"
				]
			},
			hu:{ // Hungarian
			    months: [
					"Január", "Február", "Március", "Április", "Május", "Június", "Július", "Augusztus", "Szeptember", "Október", "November", "December"
			    ],
			    dayOfWeek: [
					"Va", "Hé", "Ke", "Sze", "Cs", "Pé", "Szo"
			    ]
			}
		},
		value:'',
		lang:'en',
		
		format:	'Y/m/d H:i',
		formatTime:	'H:i',
		formatDate:	'Y/m/d',
		
		startDate:	false, // new Date(), '1986/12/08', '-1970/01/05','-1970/01/05', 
		
		step:60,
		monthChangeSpinner:true,
		closeOnDateSelect:false,
		closeOnWithoutClick:true,
		closeOnInputClick: true,
		
		timepicker:true,
		datepicker:true,
		weeks:false,
		
		defaultTime:false,		// use formatTime format (ex. '10:00' for formatTime:	'H:i')
		defaultDate:false, 		// use formatDate format (ex new Date() or '1986/12/08' or '-1970/01/05' or '-1970/01/05')
		
		minDate:false,
		maxDate:false,
		minTime:false,
		maxTime:false,
		
		allowTimes:[],
		opened:false,
		initTime:true,
		inline:false,
		
		onSelectDate:function() {},
		onSelectTime:function() {},
		onChangeMonth:function() {},
		onChangeDateTime:function() {},
		onShow:function() {},
		onClose:function() {},
		onGenerate:function() {},
		
		withoutCopyright:true,
		
		inverseButton:false,
		hours12:false,
		next:	'xdsoft_next',
		prev : 'xdsoft_prev',
		dayOfWeekStart:0,
		
		timeHeightInTimePicker:25,
		timepickerScrollbar:true,
		
		todayButton:true, // 2.1.0
		defaultSelect:true, // 2.1.0
		
		scrollMonth:true,
		scrollTime:true,
		scrollInput:true,
		
		lazyInit:false,
		
		mask:false,
		validateOnBlur:true,
		allowBlank:true,
		
		yearStart:1950,
		yearEnd:2050,
		
		style:'',
		id:'',
		
		fixed: false,
		
		roundTime:'round', // ceil, floor
		className:'',
		
		weekends	: 	[],
		yearOffset:0,
		beforeShowDay: null
	};
	
	// fix for ie8
	if ( !Array.prototype.indexOf ) {
		Array.prototype.indexOf = function(obj, start) {
			 for (var i = (start || 0), j = this.length; i < j; i++) {
				 if (this[i] === obj) { return i; }
			 }
			 return -1;
		}
	}
	
	Date.prototype.countDaysInMonth = function(){
		return new Date(this.getFullYear(), this.getMonth()+1, 0).getDate();
	};
	
	$.fn.xdsoftScroller = function( _percent ) {
		return this.each(function() {
			var timeboxparent = $(this);
			if( !$(this).hasClass('xdsoft_scroller_box') ) {
				var pointerEventToXY = function( e ) {
						var out = {x:0, y:0};
						if( e.type == 'touchstart' || e.type == 'touchmove' || e.type == 'touchend' || e.type == 'touchcancel' ) {
							var touch = e.originalEvent.touches[0] || e.originalEvent.changedTouches[0];
							out.x = touch.pageX;
							out.y = touch.pageY;
						}else if (e.type == 'mousedown' || e.type == 'mouseup' || e.type == 'mousemove' || e.type == 'mouseover'|| e.type=='mouseout' || e.type=='mouseenter' || e.type=='mouseleave') {
							out.x = e.pageX;
							out.y = e.pageY;
						}
						return out;
					},
					move = 0,
					timebox = timeboxparent.children().eq(0),
					parentHeight = timeboxparent[0].clientHeight,
					height = timebox[0].offsetHeight,
					scrollbar = $('<div class="xdsoft_scrollbar"></div>'),
					scroller = $('<div class="xdsoft_scroller"></div>'),
					maximumOffset = 100,
					start = false;

				scrollbar.append(scroller);

				timeboxparent.addClass('xdsoft_scroller_box').append(scrollbar);
				scroller.on('mousedown.xdsoft_scroller',function ( event ) {
					if( !parentHeight )
						timeboxparent.trigger('resize_scroll.xdsoft_scroller',[_percent]);
					var pageY = event.pageY,
						top = parseInt(scroller.css('margin-top')),
						h1 = scrollbar[0].offsetHeight;
					$(document.body).addClass('xdsoft_noselect');
					$([document.body,window]).on('mouseup.xdsoft_scroller',function arguments_callee() {
						$([document.body,window]).off('mouseup.xdsoft_scroller',arguments_callee)
							.off('mousemove.xdsoft_scroller',move)
							.removeClass('xdsoft_noselect');
					});
					$(document.body).on('mousemove.xdsoft_scroller',move = function(event) {
						var offset = event.pageY-pageY+top;
						if( offset<0 )
							offset = 0;
						if( offset+scroller[0].offsetHeight>h1 )
							offset = h1-scroller[0].offsetHeight;
						timeboxparent.trigger('scroll_element.xdsoft_scroller',[maximumOffset?offset/maximumOffset:0]);
					});
				});

				timeboxparent
					.on('scroll_element.xdsoft_scroller',function( event,percent ) {
						if( !parentHeight )
							timeboxparent.trigger('resize_scroll.xdsoft_scroller',[percent,true]);
						percent = percent>1?1:(percent<0||isNaN(percent))?0:percent;
						scroller.css('margin-top',maximumOffset*percent);
						timebox.css('marginTop',-parseInt((height-parentHeight)*percent))
					})
					.on('resize_scroll.xdsoft_scroller',function( event,_percent,noTriggerScroll ) {
						parentHeight = timeboxparent[0].clientHeight;
						height = timebox[0].offsetHeight;
						var percent = parentHeight/height,
							sh = percent*scrollbar[0].offsetHeight;
						if( percent>1 )
							scroller.hide();
						else{
							scroller.show();
							scroller.css('height',parseInt(sh>10?sh:10));
							maximumOffset = scrollbar[0].offsetHeight-scroller[0].offsetHeight;
							if( noTriggerScroll!==true )
								timeboxparent.trigger('scroll_element.xdsoft_scroller',[_percent?_percent:Math.abs(parseInt(timebox.css('marginTop')))/(height-parentHeight)]);
						}
					});
				timeboxparent.mousewheel&&timeboxparent.mousewheel(function(event, delta, deltaX, deltaY) {
					var top = Math.abs(parseInt(timebox.css('marginTop')));
					timeboxparent.trigger('scroll_element.xdsoft_scroller',[(top-delta*20)/(height-parentHeight)]);
					event.stopPropagation();
					return false;
				});
				timeboxparent.on('touchstart',function( event ) {
					start = pointerEventToXY(event);
				});
				timeboxparent.on('touchmove',function( event ) {
					if( start ) {
						var coord = pointerEventToXY(event), top = Math.abs(parseInt(timebox.css('marginTop')));
						timeboxparent.trigger('scroll_element.xdsoft_scroller',[(top-(coord.y-start.y))/(height-parentHeight)]);
						event.stopPropagation();
						event.preventDefault();
						start = pointerEventToXY(event);
					}
				});
				timeboxparent.on('touchend touchcancel',function( event ) {
					start = false;
				});
			}
			timeboxparent.trigger('resize_scroll.xdsoft_scroller',[_percent]);
		});
	};
	$.fn.datetimepicker = function( opt ) {
		var KEY0 = 48,
			KEY9 = 57,
			_KEY0 = 96,
			_KEY9 = 105,
			CTRLKEY = 17,
			DEL = 46,
			ENTER = 13,
			ESC = 27,
			BACKSPACE = 8,
			ARROWLEFT = 37,
			ARROWUP = 38,
			ARROWRIGHT = 39,
			ARROWDOWN = 40,
			TAB = 9,
			F5 = 116,
			AKEY = 65,
			CKEY = 67,
			VKEY = 86,
			ZKEY = 90,
			YKEY = 89,
			ctrlDown	=	false,
			options = ($.isPlainObject(opt)||!opt)?$.extend(true,{},default_options,opt):$.extend({},default_options),

			lazyInitTimer = 0,

			lazyInit = function( input ){
				input
					.on('open.xdsoft focusin.xdsoft mousedown.xdsoft',function initOnActionCallback(event) {
						if( input.is(':disabled')||input.is(':hidden')||!input.is(':visible')||input.data( 'xdsoft_datetimepicker') )
							return;
				
						clearTimeout(lazyInitTimer);
						
						lazyInitTimer = setTimeout(function() {

							if( !input.data( 'xdsoft_datetimepicker') )
								createDateTimePicker(input);
								
							input
								.off('open.xdsoft focusin.xdsoft mousedown.xdsoft',initOnActionCallback)
								.trigger('open.xdsoft');
						},100);
						
					});
			},
			
			createDateTimePicker = function( input ) {
				
				var datetimepicker = $('<div '+(options.id?'id="'+options.id+'"':'')+' '+(options.style?'style="'+options.style+'"':'')+' class="xdsoft_datetimepicker xdsoft_noselect '+(options.weeks?' xdsoft_showweeks':'')+options.className+'"></div>'),
					xdsoft_copyright = $('<div class="xdsoft_copyright"><a target="_blank" href="http://xdsoft.net/jqplugins/datetimepicker/">xdsoft.net</a></div>'),
					datepicker = $('<div class="xdsoft_datepicker active"></div>'),
					mounth_picker = $('<div class="xdsoft_mounthpicker"><button type="button" class="xdsoft_prev"></button><button type="button" class="xdsoft_today_button"></button><div class="xdsoft_label xdsoft_month"><span></span></div><div class="xdsoft_label xdsoft_year"><span></span></div><button type="button" class="xdsoft_next"></button></div>'),
					calendar = $('<div class="xdsoft_calendar"></div>'),
					timepicker = $('<div class="xdsoft_timepicker active"><button type="button" class="xdsoft_prev"></button><div class="xdsoft_time_box"></div><button type="button" class="xdsoft_next"></button></div>'),
					timeboxparent = timepicker.find('.xdsoft_time_box').eq(0),
					timebox = $('<div class="xdsoft_time_variant"></div>'),
					scrollbar = $('<div class="xdsoft_scrollbar"></div>'),
					scroller = $('<div class="xdsoft_scroller"></div>'),
					monthselect =$('<div class="xdsoft_select xdsoft_monthselect"><div></div></div>'),
					yearselect =$('<div class="xdsoft_select xdsoft_yearselect"><div></div></div>');

				//constructor lego
				mounth_picker
					.find('.xdsoft_month span')
						.after(monthselect);
				mounth_picker
					.find('.xdsoft_year span')
						.after(yearselect);

				mounth_picker
					.find('.xdsoft_month,.xdsoft_year')
						.on('mousedown.xdsoft',function(event) {
							mounth_picker
								.find('.xdsoft_select')
									.hide();
									
							var select = $(this).find('.xdsoft_select').eq(0),
								val = 0,
								top = 0;

							if( _xdsoft_datetime.currentTime )
								val = _xdsoft_datetime.currentTime[$(this).hasClass('xdsoft_month')?'getMonth':'getFullYear']();

							select.show();
							
							for(var items = select.find('div.xdsoft_option'),i = 0;i<items.length;i++) {
								if( items.eq(i).data('value')==val ) {
									break;
								}else top+=items[0].offsetHeight;
							}

							select.xdsoftScroller(top/(select.children()[0].offsetHeight-(select[0].clientHeight)));
							event.stopPropagation();
							
							return false;
						});

				mounth_picker
					.find('.xdsoft_select')
						.xdsoftScroller()
						.on('mousedown.xdsoft',function( event ) {
							event.stopPropagation();
							event.preventDefault();
						})
						.on('mousedown.xdsoft','.xdsoft_option',function( event ) {
							if( _xdsoft_datetime&&_xdsoft_datetime.currentTime )
								_xdsoft_datetime.currentTime[$(this).parent().parent().hasClass('xdsoft_monthselect')?'setMonth':'setFullYear']($(this).data('value'));
							
							$(this).parent().parent().hide();
							
							datetimepicker.trigger('xchange.xdsoft');
							options.onChangeMonth&&options.onChangeMonth.call&&options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						});


				// set options
				datetimepicker.setOptions = function( _options ) {
					options = $.extend(true,{},options,_options);
					
					if( _options.allowTimes && $.isArray(_options.allowTimes) && _options.allowTimes.length ){
						options['allowTimes'] = $.extend(true,[],_options.allowTimes);
					}
					
					if( _options.weekends && $.isArray(_options.weekends) && _options.weekends.length ){
						options['weekends'] = $.extend(true,[],_options.weekends);
					}
					
					if( (options.open||options.opened)&&(!options.inline) ) {
						input.trigger('open.xdsoft');
					}

					if( options.inline ) {
						triggerAfterOpen = true;
						datetimepicker.addClass('xdsoft_inline');
						input.after(datetimepicker).hide();
					}

					if( options.inverseButton ) {
						options.next = 'xdsoft_prev';
						options.prev = 'xdsoft_next';
					}

					if( options.datepicker )
						datepicker.addClass('active');
					else
						datepicker.removeClass('active');

					if( options.timepicker )
						timepicker.addClass('active');
					else
						timepicker.removeClass('active');

					if( options.value ){
						input&&input.val&&input.val(options.value);
						_xdsoft_datetime.setCurrentTime(options.value);
					}

					if( isNaN(options.dayOfWeekStart) )
						options.dayOfWeekStart = 0;
					else
						options.dayOfWeekStart = parseInt(options.dayOfWeekStart)%7;

					if( !options.timepickerScrollbar )
						scrollbar.hide();
					
					if( options.minDate && /^-(.*)$/.test(options.minDate) ){
						options.minDate = _xdsoft_datetime.strToDateTime(options.minDate).dateFormat( options.formatDate );
					}
					
					if( options.maxDate &&  /^\+(.*)$/.test(options.maxDate) ) {
						options.maxDate = _xdsoft_datetime.strToDateTime(options.maxDate).dateFormat( options.formatDate );
					}
					
					mounth_picker
						.find('.xdsoft_today_button')
							.css('visibility',!options.todayButton?'hidden':'visible');

					if( options.mask ) {
						var e,
							getCaretPos = function ( input ) {
								try{
									if ( document.selection && document.selection.createRange ) {
										var range = document.selection.createRange();
										return range.getBookmark().charCodeAt(2) - 2;
									}else
										if ( input.setSelectionRange )
											return input.selectionStart;
								}catch(e) {
									return 0;
								}
							},
							setCaretPos = function ( node,pos ) {
								node = (typeof node == "string" || node instanceof String) ? document.getElementById(node) : node;
								if(!node) {
									return false;
								}else if(node.createTextRange) {
									var textRange = node.createTextRange();
									textRange.collapse(true);
									textRange.moveEnd(pos);
									textRange.moveStart(pos);
									textRange.select();
									return true;
								}else if(node.setSelectionRange) {
									node.setSelectionRange(pos,pos);
									return true;
								}
								return false;
							},
							isValidValue = function ( mask,value ) {
								var reg = mask
									.replace(/([\[\]\/\{\}\(\)\-\.\+]{1})/g,'\\$1')
									.replace(/_/g,'{digit+}')
									.replace(/([0-9]{1})/g,'{digit$1}')
									.replace(/\{digit([0-9]{1})\}/g,'[0-$1_]{1}')
									.replace(/\{digit[\+]\}/g,'[0-9_]{1}');
								return RegExp(reg).test(value);
							};
						input.off('keydown.xdsoft');
						switch(true) {
							case ( options.mask===true ):
							
								options.mask = options.format
									.replace(/Y/g,'9999')
									.replace(/F/g,'9999')
									.replace(/m/g,'19')
									.replace(/d/g,'39')
									.replace(/H/g,'29')
									.replace(/i/g,'59')
									.replace(/s/g,'59');
									
							case ( $.type(options.mask) == 'string' ):
							
								if( !isValidValue( options.mask,input.val() ) )
									input.val(options.mask.replace(/[0-9]/g,'_'));

								input.on('keydown.xdsoft',function( event ) {
									var val = this.value,
										key = event.which;
										
									switch(true) {
										case (( key>=KEY0&&key<=KEY9 )||( key>=_KEY0&&key<=_KEY9 ))||(key==BACKSPACE||key==DEL):
											var pos = getCaretPos(this),
												digit = ( key!=BACKSPACE&&key!=DEL )?String.fromCharCode((_KEY0 <= key && key <= _KEY9)? key-KEY0 : key):'_';
											
											if( (key==BACKSPACE||key==DEL)&&pos ) {
												pos--;
												digit='_';
											}
											
											while( /[^0-9_]/.test(options.mask.substr(pos,1))&&pos<options.mask.length&&pos>0 )
												pos+=( key==BACKSPACE||key==DEL )?-1:1;

											val = val.substr(0,pos)+digit+val.substr(pos+1);
											if( $.trim(val)=='' ){
												val = options.mask.replace(/[0-9]/g,'_');
											}else{
												if( pos==options.mask.length )
													break;
											}
											
											pos+=(key==BACKSPACE||key==DEL)?0:1;
											while( /[^0-9_]/.test(options.mask.substr(pos,1))&&pos<options.mask.length&&pos>0 )
												pos+=(key==BACKSPACE||key==DEL)?-1:1;
												
											if( isValidValue( options.mask,val ) ) {
												this.value = val;
												setCaretPos(this,pos);
											}else if( $.trim(val)=='' )
												this.value = options.mask.replace(/[0-9]/g,'_');
											else{
												input.trigger('error_input.xdsoft');
											}
										break;
										case ( !!~([AKEY,CKEY,VKEY,ZKEY,YKEY].indexOf(key))&&ctrlDown ):
										 case !!~([ESC,ARROWUP,ARROWDOWN,ARROWLEFT,ARROWRIGHT,F5,CTRLKEY,TAB,ENTER].indexOf(key)):
										return true;
									}
									event.preventDefault();
									return false;
								});
							break;
						}
					}
					if( options.validateOnBlur ) {
						input
							.off('blur.xdsoft')
							.on('blur.xdsoft', function() {
								if( options.allowBlank && !$.trim($(this).val()).length ) {
									$(this).val(null);
									datetimepicker.data('xdsoft_datetime').empty();
								}else if( !Date.parseDate( $(this).val(), options.format ) ) {
									$(this).val((_xdsoft_datetime.now()).dateFormat( options.format ));
									datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val());
								}
								else{
									datetimepicker.data('xdsoft_datetime').setCurrentTime($(this).val());
 								}
								datetimepicker.trigger('changedatetime.xdsoft');
							});
					}
					options.dayOfWeekStartPrev = (options.dayOfWeekStart==0)?6:options.dayOfWeekStart-1;
					
					datetimepicker
						.trigger('xchange.xdsoft')
						.trigger('afterOpen.xdsoft')
				};

				datetimepicker
					.data('options',options)
					.on('mousedown.xdsoft',function( event ) {
						event.stopPropagation();
						event.preventDefault();
						yearselect.hide();
						monthselect.hide();
						return false;
					});

				var scroll_element = timepicker.find('.xdsoft_time_box');
				scroll_element.append(timebox);
				scroll_element.xdsoftScroller();
				
				datetimepicker.on('afterOpen.xdsoft',function() {
					scroll_element.xdsoftScroller();
				});

				datetimepicker
					.append(datepicker)
					.append(timepicker);

				if( options.withoutCopyright!==true )
					datetimepicker
						.append(xdsoft_copyright);

				datepicker
					.append(mounth_picker)
					.append(calendar);

				$('body').append(datetimepicker);

				var _xdsoft_datetime = new function() {
					var _this = this;
					_this.now = function( norecursion ) {
						var d = new Date();
						
						if( !norecursion && options.defaultDate  ){
							var date = _this.strToDate(options.defaultDate);
							d.setFullYear( date.getFullYear() );
							d.setMonth( date.getMonth() );
							d.setDate( date.getDate() );
						}
						
						if( options.yearOffset  ){
							d.setFullYear(d.getFullYear()+options.yearOffset);
						}
						
						if( !norecursion && options.defaultTime ){
							var time = _this.strtotime(options.defaultTime);
							d.setHours( time.getHours() );
							d.setMinutes( time.getMinutes() );
						}
							
						return d;
					};

					
					_this.isValidDate = function (d) {
						if ( Object.prototype.toString.call(d) !== "[object Date]" )
							return false;
						return !isNaN(d.getTime());
					};

					_this.setCurrentTime = function( dTime ) {
						_this.currentTime = (typeof dTime == 'string')? _this.strToDateTime(dTime) : _this.isValidDate(dTime) ? dTime: _this.now();
						datetimepicker.trigger('xchange.xdsoft');
					};

					_this.empty = function() {
						_this.currentTime = null;
					};

					_this.getCurrentTime = function( dTime) {
						return _this.currentTime;
					};

					_this.nextMonth = function() {
						var month = _this.currentTime.getMonth()+1;
						if( month==12 ) {
							_this.currentTime.setFullYear(_this.currentTime.getFullYear()+1);
							month = 0;
						}
						_this.currentTime.setDate(
							Math.min(
								// Day 0 is the last day in the previous month, but we want to know the number of days in the current month, so we need to evaluate the subsequent month (month+1)
								new Date(_this.currentTime.getFullYear(), month+1, 0).getDate(),
								_this.currentTime.getDate()
							)
						);
						_this.currentTime.setMonth(month);
						options.onChangeMonth&&options.onChangeMonth.call&&options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						datetimepicker.trigger('xchange.xdsoft');
						return month;
					};

					_this.prevMonth = function() {
						var month = _this.currentTime.getMonth()-1;
						if( month==-1 ) {
							_this.currentTime.setFullYear(_this.currentTime.getFullYear()-1);
							month = 11;
						}
						_this.currentTime.setDate(
							Math.min(
								// Day 0 is the last day in the previous month, but we want to know the number of days in the current month, so we need to evaluate the subsequent month (month+1)
								new Date(_this.currentTime.getFullYear(), month+1, 0).getDate(),
								_this.currentTime.getDate()
							)
						);
						_this.currentTime.setMonth(month);
						options.onChangeMonth&&options.onChangeMonth.call&&options.onChangeMonth.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						datetimepicker.trigger('xchange.xdsoft');
						return month;
					};

					_this.strToDateTime = function( sDateTime ) {
						if( sDateTime && sDateTime instanceof Date && _this.isValidDate(sDateTime) )
							return sDateTime;
						
						var tmpDate = [],timeOffset,currentTime;
					
						if( ( tmpDate = /^(\+|\-)(.*)$/.exec(sDateTime) )  && ( tmpDate[2]=Date.parseDate(tmpDate[2], options.formatDate) ) ) {
							timeOffset = tmpDate[2].getTime()-(tmpDate[2].getTimezoneOffset())*60000;
							currentTime = new Date((_xdsoft_datetime.now()).getTime()+parseInt(tmpDate[1]+'1')*timeOffset);
						}else
							currentTime = sDateTime?Date.parseDate(sDateTime, options.format):_this.now();
							
						if( !_this.isValidDate(currentTime) )
							currentTime = _this.now();
							
						return currentTime;
					};

					_this.strToDate = function( sDate ) {
						if( sDate && sDate instanceof Date && _this.isValidDate(sDate) )
							return sDate;
						
						var currentTime = sDate?Date.parseDate(sDate, options.formatDate):_this.now(true);
						if( !_this.isValidDate(currentTime) )
							currentTime = _this.now(true);
							
						return currentTime;
					};

					_this.strtotime = function( sTime ) {
						if( sTime && sTime instanceof Date && _this.isValidDate(sTime) )
							return sTime;
							
						var currentTime = sTime?Date.parseDate(sTime, options.formatTime):_this.now();
						if( !_this.isValidDate(currentTime) )
							currentTime = _this.now(true);
							
						return currentTime;
					};

					_this.str = function() {
						return _this.currentTime.dateFormat(options.format);
					};
					
					_this.currentTime = this.now();
				};
				mounth_picker
					.find('.xdsoft_today_button')
						.on('mousedown.xdsoft',function() {
							datetimepicker.data('changed',true);
							_xdsoft_datetime.setCurrentTime(0);
							datetimepicker.trigger('afterOpen.xdsoft');
						}).on('dblclick.xdsoft',function(){
							input.val( _xdsoft_datetime.str() );
							datetimepicker.trigger('close.xdsoft');
						});
				mounth_picker
					.find('.xdsoft_prev,.xdsoft_next')
						.on('mousedown.xdsoft',function() {
							var $this = $(this),
								timer = 0,
								stop = false;

							(function arguments_callee1(v) {
								var month =  _xdsoft_datetime.currentTime.getMonth();
								if( $this.hasClass( options.next ) ) {
									_xdsoft_datetime.nextMonth();
								}else if( $this.hasClass( options.prev ) ) {
									_xdsoft_datetime.prevMonth();
								}
								if (options.monthChangeSpinner) {
									!stop&&(timer = setTimeout(arguments_callee1,v?v:100));
								}
							})(500);

							$([document.body,window]).on('mouseup.xdsoft',function arguments_callee2() {
								clearTimeout(timer);
								stop = true;
								$([document.body,window]).off('mouseup.xdsoft',arguments_callee2);
							});
						});

				timepicker
					.find('.xdsoft_prev,.xdsoft_next')
						.on('mousedown.xdsoft',function() {
							var $this = $(this),
								timer = 0,
								stop = false,
								period = 110;
							(function arguments_callee4(v) {
								var pheight = timeboxparent[0].clientHeight,
									height = timebox[0].offsetHeight,
									top = Math.abs(parseInt(timebox.css('marginTop')));
								if( $this.hasClass(options.next) && (height-pheight)- options.timeHeightInTimePicker>=top ) {
									timebox.css('marginTop','-'+(top+options.timeHeightInTimePicker)+'px')
								}else if( $this.hasClass(options.prev) && top-options.timeHeightInTimePicker>=0  ) {
									timebox.css('marginTop','-'+(top-options.timeHeightInTimePicker)+'px')
								}
								timeboxparent.trigger('scroll_element.xdsoft_scroller',[Math.abs(parseInt(timebox.css('marginTop'))/(height-pheight))]);
								period= ( period>10 )?10:period-10;
								!stop&&(timer = setTimeout(arguments_callee4,v?v:period));
							})(500);
							$([document.body,window]).on('mouseup.xdsoft',function arguments_callee5() {
								clearTimeout(timer);
								stop = true;
								$([document.body,window])
									.off('mouseup.xdsoft',arguments_callee5);
							});
						});

				var xchangeTimer = 0;
				// base handler - generating a calendar and timepicker
				datetimepicker
					.on('xchange.xdsoft',function( event ) {
						clearTimeout(xchangeTimer);
						xchangeTimer = setTimeout(function(){
							var table 	=	'',
									start	= new Date(_xdsoft_datetime.currentTime.getFullYear(),_xdsoft_datetime.currentTime.getMonth(),1, 12, 0, 0),
									i = 0,
									today = _xdsoft_datetime.now();
								
								while( start.getDay()!=options.dayOfWeekStart )
									start.setDate(start.getDate()-1);

								//generate calendar
								table+='<table><thead><tr>';

								if(options.weeks) {
									table+='<th></th>';
								}

								// days
								for(var j = 0; j<7; j++) {
									table+='<th>'+options.i18n[options.lang].dayOfWeek[(j+options.dayOfWeekStart)%7]+'</th>';
								}

								table+='</tr></thead>';
								table+='<tbody>';
								var maxDate = false, minDate = false;
								
								if( options.maxDate!==false ) {
									maxDate = _xdsoft_datetime.strToDate(options.maxDate);
									maxDate = new Date(maxDate.getFullYear(),maxDate.getMonth(),maxDate.getDate(),23,59,59,999);
								}
								
								if( options.minDate!==false ) {
									minDate = _xdsoft_datetime.strToDate(options.minDate);
									minDate = new Date(minDate.getFullYear(),minDate.getMonth(),minDate.getDate());
								}
								
								var d,y,m,w,classes = [],customDateSettings,newRow=true;
								
								while( i<_xdsoft_datetime.currentTime.countDaysInMonth()||start.getDay()!=options.dayOfWeekStart||_xdsoft_datetime.currentTime.getMonth()==start.getMonth() ) {
									classes = [];
									i++;

									d = start.getDate(); y = start.getFullYear(); m = start.getMonth(); w = start.getWeekOfYear();

									classes.push('xdsoft_date');

									if ( options.beforeShowDay && options.beforeShowDay.call ) {
										customDateSettings = options.beforeShowDay.call(datetimepicker, start);
									} else {
										customDateSettings = null;
									}

									if( ( maxDate!==false && start > maxDate )||(  minDate!==false && start < minDate )||(customDateSettings && customDateSettings[0] === false) ){
										classes.push('xdsoft_disabled');
									}

									if ( customDateSettings && customDateSettings[1] != "" ) {
										classes.push(customDateSettings[1]);
									}

									if( _xdsoft_datetime.currentTime.getMonth()!=m ) classes.push('xdsoft_other_month');

									if( (options.defaultSelect||datetimepicker.data('changed')) && _xdsoft_datetime.currentTime.dateFormat( options.formatDate )==start.dateFormat( options.formatDate ) ) {
										classes.push('xdsoft_current');
									}

									if( today.dateFormat( options.formatDate )==start.dateFormat( options.formatDate ) ) {
										classes.push('xdsoft_today');
									}

									if( start.getDay()==0||start.getDay()==6||~options.weekends.indexOf(start.dateFormat( options.formatDate )) ) {
										classes.push('xdsoft_weekend');
									}

									if(options.beforeShowDay && typeof options.beforeShowDay == 'function') {
										classes.push(options.beforeShowDay(start))
									}

									if(newRow) {
										table+='<tr>';
										newRow = false;
										
										if(options.weeks) {
											table+='<th>'+w+'</th>';
										}
									}

									table+='<td data-date="'+d+'" data-month="'+m+'" data-year="'+y+'"'+' class="xdsoft_date xdsoft_day_of_week'+start.getDay()+' '+ classes.join(' ')+'">'+
												'<div>'+d+'</div>'+
											'</td>';

									if( start.getDay()==options.dayOfWeekStartPrev ) {
										table+='</tr>';
										newRow = true;
									}

									start.setDate(d+1);
								}
								table+='</tbody></table>';

								calendar.html(table);

								mounth_picker.find('.xdsoft_label span').eq(0).text(options.i18n[options.lang].months[_xdsoft_datetime.currentTime.getMonth()]);
								mounth_picker.find('.xdsoft_label span').eq(1).text(_xdsoft_datetime.currentTime.getFullYear());

								// generate timebox
								var time = '',
									h = '',
									m ='',
									line_time = function line_time( h,m ) {
										var now = _xdsoft_datetime.now();
										now.setHours(h);
										h = parseInt(now.getHours());
										now.setMinutes(m);
										m = parseInt(now.getMinutes());

										classes = [];
										if( (options.maxTime!==false&&_xdsoft_datetime.strtotime(options.maxTime).getTime()<now.getTime())||(options.minTime!==false&&_xdsoft_datetime.strtotime(options.minTime).getTime()>now.getTime()))
											classes.push('xdsoft_disabled');
										if( (options.initTime||options.defaultSelect||datetimepicker.data('changed')) && parseInt(_xdsoft_datetime.currentTime.getHours())==parseInt(h)&&(options.step>59||Math[options.roundTime](_xdsoft_datetime.currentTime.getMinutes()/options.step)*options.step==parseInt(m))) {
											if( options.defaultSelect||datetimepicker.data('changed')) {
												classes.push('xdsoft_current');
											} else if( options.initTime ) {
												classes.push('xdsoft_init_time');
											}
										}
										if( parseInt(today.getHours())==parseInt(h)&&parseInt(today.getMinutes())==parseInt(m))
											classes.push('xdsoft_today');
										time+= '<div class="xdsoft_time '+classes.join(' ')+'" data-hour="'+h+'" data-minute="'+m+'">'+now.dateFormat(options.formatTime)+'</div>';
									};

								if( !options.allowTimes || !$.isArray(options.allowTimes) || !options.allowTimes.length ) {
									for( var i=0,j=0;i<(options.hours12?12:24);i++ ) {
										for( j=0;j<60;j+=options.step ) {
											h = (i<10?'0':'')+i;
											m = (j<10?'0':'')+j;
											line_time( h,m );
										}
									}
								}else{
									for( var i=0;i<options.allowTimes.length;i++ ) {
										h = _xdsoft_datetime.strtotime(options.allowTimes[i]).getHours();
										m = _xdsoft_datetime.strtotime(options.allowTimes[i]).getMinutes();
										line_time( h,m );
									}
								}

								timebox.html(time);

								var opt = '',
									i = 0;

								for( i = parseInt(options.yearStart,10)+options.yearOffset;i<= parseInt(options.yearEnd,10)+options.yearOffset;i++ ) {
									opt+='<div class="xdsoft_option '+(_xdsoft_datetime.currentTime.getFullYear()==i?'xdsoft_current':'')+'" data-value="'+i+'">'+i+'</div>';
								}
								yearselect.children().eq(0)
														.html(opt);

								for( i = 0,opt = '';i<= 11;i++ ) {
									opt+='<div class="xdsoft_option '+(_xdsoft_datetime.currentTime.getMonth()==i?'xdsoft_current':'')+'" data-value="'+i+'">'+options.i18n[options.lang].months[i]+'</div>';
								}
								monthselect.children().eq(0).html(opt);
								$(datetimepicker)
									.trigger('generate.xdsoft');
						},10);
						event.stopPropagation();
					})
					.on('afterOpen.xdsoft',function() {
						if( options.timepicker ) {
							var classType;
							if( timebox.find('.xdsoft_current').length ) {
								classType = '.xdsoft_current';
							} else if( timebox.find('.xdsoft_init_time').length ) {
								classType = '.xdsoft_init_time';
							}
							
							if( classType ) {
								var pheight = timeboxparent[0].clientHeight,
									height = timebox[0].offsetHeight,
									top = timebox.find(classType).index()*options.timeHeightInTimePicker+1;
								if( (height-pheight)<top )
									top = height-pheight;
								timeboxparent.trigger('scroll_element.xdsoft_scroller',[parseInt(top)/(height-pheight)]);
							}else{
								timeboxparent.trigger('scroll_element.xdsoft_scroller',[0]);
							}
						}
					});
				
				var timerclick = 0;
				
				calendar
					.on('click.xdsoft', 'td', function (xdevent) {
					  xdevent.stopPropagation();  // Prevents closing of Pop-ups, Modals and Flyouts in Bootstrap
						timerclick++;
						var $this = $(this),
							currentTime = _xdsoft_datetime.currentTime;
						
						if( currentTime===undefined||currentTime===null ){
                            _xdsoft_datetime.currentTime = _xdsoft_datetime.now();
                            currentTime = _xdsoft_datetime.currentTime;
                        }
						
						if( $this.hasClass('xdsoft_disabled') )
							return false;

						currentTime.setDate( 1 );
						currentTime.setFullYear( $this.data('year') );
						currentTime.setMonth( $this.data('month') );
						currentTime.setDate( $this.data('date') );
						
						datetimepicker.trigger('select.xdsoft',[currentTime]);

						input.val( _xdsoft_datetime.str() );
						if( (timerclick>1||(options.closeOnDateSelect===true||( options.closeOnDateSelect===0&&!options.timepicker )))&&!options.inline ) {
							datetimepicker.trigger('close.xdsoft');
						}

						if( options.onSelectDate &&	options.onSelectDate.call ) {
							options.onSelectDate.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						}

						datetimepicker.data('changed',true);
						datetimepicker.trigger('xchange.xdsoft');
						datetimepicker.trigger('changedatetime.xdsoft');
						setTimeout(function(){
							timerclick = 0;
						},200);
					});

				timebox
					.on('click.xdsoft', 'div', function (xdevent) {
					    xdevent.stopPropagation(); // NAJ: Prevents closing of Pop-ups, Modals and Flyouts
						var $this = $(this),
							currentTime = _xdsoft_datetime.currentTime;
						
						if( currentTime===undefined||currentTime===null ){
                            _xdsoft_datetime.currentTime = _xdsoft_datetime.now();
                            currentTime = _xdsoft_datetime.currentTime;
                        }
						
						if( $this.hasClass('xdsoft_disabled') )
							return false;
						currentTime.setHours($this.data('hour'));
						currentTime.setMinutes($this.data('minute'));
						datetimepicker.trigger('select.xdsoft',[currentTime]);

						datetimepicker.data('input').val( _xdsoft_datetime.str() );

						!options.inline&&datetimepicker.trigger('close.xdsoft');

						if( options.onSelectTime&&options.onSelectTime.call ) {
							options.onSelectTime.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						}
						datetimepicker.data('changed',true);
						datetimepicker.trigger('xchange.xdsoft');
						datetimepicker.trigger('changedatetime.xdsoft');
					});

				datetimepicker.mousewheel&&datepicker.mousewheel(function(event, delta, deltaX, deltaY) {
					if( !options.scrollMonth )
						return true;
					if( delta<0 )
						_xdsoft_datetime.nextMonth();
					else
						_xdsoft_datetime.prevMonth();
					return false;
				});

				datetimepicker.mousewheel&&timeboxparent.unmousewheel().mousewheel(function(event, delta, deltaX, deltaY) {
					if( !options.scrollTime )
						return true;
					var pheight = timeboxparent[0].clientHeight,
						height = timebox[0].offsetHeight,
						top = Math.abs(parseInt(timebox.css('marginTop'))),
						fl = true;
					if( delta<0 && (height-pheight)-options.timeHeightInTimePicker>=top ) {
						timebox.css('marginTop','-'+(top+options.timeHeightInTimePicker)+'px');
						fl = false;
					}else if( delta>0&&top-options.timeHeightInTimePicker>=0 ) {
						timebox.css('marginTop','-'+(top-options.timeHeightInTimePicker)+'px');
						fl = false;
					}
					timeboxparent.trigger('scroll_element.xdsoft_scroller',[Math.abs(parseInt(timebox.css('marginTop'))/(height-pheight))]);
					event.stopPropagation();
					return fl;
				});
				
				var triggerAfterOpen = false;
				datetimepicker
					.on('changedatetime.xdsoft',function() {
						if( options.onChangeDateTime&&options.onChangeDateTime.call ) {
							var $input = datetimepicker.data('input');
							options.onChangeDateTime.call(datetimepicker, _xdsoft_datetime.currentTime, $input);
							delete options.value;
							$input.trigger('change');
						}
					})
					.on('generate.xdsoft',function() {
						if( options.onGenerate&&options.onGenerate.call )
							options.onGenerate.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						if( triggerAfterOpen ){
							datetimepicker.trigger('afterOpen.xdsoft');
							triggerAfterOpen = false;
						}
					})
					.on( 'click.xdsoft', function( xdevent )
					{
						xdevent.stopPropagation();  // Prevents closing of Pop-ups, Modals and Flyouts in Bootstrap
					});

				var current_time_index = 0;
				input.mousewheel&&input.mousewheel(function( event, delta, deltaX, deltaY ) {
					if( !options.scrollInput )
						return true;
					if( !options.datepicker && options.timepicker ) {
						current_time_index = timebox.find('.xdsoft_current').length?timebox.find('.xdsoft_current').eq(0).index():0;
						if( current_time_index+delta>=0&&current_time_index+delta<timebox.children().length )
							current_time_index+=delta;
						timebox.children().eq(current_time_index).length&&timebox.children().eq(current_time_index).trigger('mousedown');
						return false;
					}else if( options.datepicker && !options.timepicker ) {
						datepicker.trigger( event, [delta, deltaX, deltaY]);
						input.val&&input.val( _xdsoft_datetime.str() );
						datetimepicker.trigger('changedatetime.xdsoft');
						return false;
					}
				});
				var setPos = function() {
					var offset = datetimepicker.data('input').offset(), top = offset.top+datetimepicker.data('input')[0].offsetHeight-1, left = offset.left, position = "absolute";
					if (options.fixed) {
						top -= $(window).scrollTop();
						left -= $(window).scrollLeft();
						position = "fixed";
					}else {
						if( top+datetimepicker[0].offsetHeight>$(window).height()+$(window).scrollTop() )
							top = offset.top-datetimepicker[0].offsetHeight+1;
							if (top < 0)
								top = 0;
						if( left+datetimepicker[0].offsetWidth>$(window).width() )
							left = offset.left-datetimepicker[0].offsetWidth+datetimepicker.data('input')[0].offsetWidth;
					}
					datetimepicker.css({
						left:left,
						top:top,
						position: position
					});
				};
				datetimepicker
					.on('open.xdsoft', function() {
						var onShow = true;
						if( options.onShow&&options.onShow.call) {
							onShow = options.onShow.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						}
						if( onShow!==false ) {
							datetimepicker.show();
							setPos();
							$(window)
								.off('resize.xdsoft',setPos)
								.on('resize.xdsoft',setPos);

							if( options.closeOnWithoutClick ) {
								$([document.body,window]).on('mousedown.xdsoft',function arguments_callee6() {
									datetimepicker.trigger('close.xdsoft');
									$([document.body,window]).off('mousedown.xdsoft',arguments_callee6);
								});
							}
						}
					})
					.on('close.xdsoft', function( event ) {
						var onClose = true;
						if( options.onClose&&options.onClose.call ) {
							onClose=options.onClose.call(datetimepicker,_xdsoft_datetime.currentTime,datetimepicker.data('input'));
						}
						if( onClose!==false&&!options.opened&&!options.inline ) {
							datetimepicker.hide();
						}
						event.stopPropagation();
					})
					.data('input',input);

				var timer = 0,
					timer1 = 0;

				datetimepicker.data('xdsoft_datetime',_xdsoft_datetime);
				datetimepicker.setOptions(options);
				
				function getCurrentValue(){

					var ct = false;

                    if ( options.startDate ) {
                        ct = _xdsoft_datetime.strToDate(options.startDate);
                    } else {
                        ct = options.value?options.value:(input&&input.val&&input.val())?input.val():'';
						if( ct ) {
							ct = _xdsoft_datetime.strToDateTime(ct);
						} else if ( options.defaultDate ) {
							ct = _xdsoft_datetime.strToDate(options.defaultDate);
						}
                    }

					if ( ct && _xdsoft_datetime.isValidDate(ct) ) {
						datetimepicker.data('changed',true);
					} else {
                        ct = '';
                    }
					
					return ct?ct:0;
				}
				//debugger
				_xdsoft_datetime.setCurrentTime( getCurrentValue() );

				input
					.data( 'xdsoft_datetimepicker',datetimepicker )
					.on('open.xdsoft focusin.xdsoft mousedown.xdsoft',function(event) {
						if( input.is(':disabled')||input.is(':hidden')||!input.is(':visible')||(input.data('xdsoft_datetimepicker').is(':visible') && options.closeOnInputClick) )
							return;
						clearTimeout(timer);
						timer = setTimeout(function() {
							if( input.is(':disabled')||input.is(':hidden')||!input.is(':visible') )
								return;
								
							triggerAfterOpen = true;
							_xdsoft_datetime.setCurrentTime(getCurrentValue());
							
							datetimepicker.trigger('open.xdsoft');
						},100);
					})
					.on('keydown.xdsoft',function( event ) {
						var val = this.value,
							key = event.which;
						switch(true) {
							case !!~([ENTER].indexOf(key)):
								var elementSelector = $("input:visible,textarea:visible");
								datetimepicker.trigger('close.xdsoft');
								elementSelector.eq(elementSelector.index(this) + 1).focus();
							return false;
							case !!~[TAB].indexOf(key):
								datetimepicker.trigger('close.xdsoft');
							return true;
						}
					});
			},
			destroyDateTimePicker = function( input ) {
				var datetimepicker = input.data('xdsoft_datetimepicker');
				if( datetimepicker ) {
					datetimepicker.data('xdsoft_datetime',null);
					datetimepicker.remove();
					input
						.data( 'xdsoft_datetimepicker',null )
						.off( 'open.xdsoft focusin.xdsoft focusout.xdsoft mousedown.xdsoft blur.xdsoft keydown.xdsoft' );
					$(window).off('resize.xdsoft');
					$([window,document.body]).off('mousedown.xdsoft');
					input.unmousewheel&&input.unmousewheel();
				}
			};
		$(document)
			.off('keydown.xdsoftctrl keyup.xdsoftctrl')
			.on('keydown.xdsoftctrl',function(e) {
				if ( e.keyCode == CTRLKEY )
					ctrlDown = true;
			})
			.on('keyup.xdsoftctrl',function(e) {
				if ( e.keyCode == CTRLKEY )
					ctrlDown = false;
			});
		return this.each(function() {
			var datetimepicker;
			if( datetimepicker = $(this).data('xdsoft_datetimepicker') ) {
				if( $.type(opt) === 'string' ) {
					switch(opt) {
						case 'show':
							$(this).select().focus();
							datetimepicker.trigger( 'open.xdsoft' );
						break;
						case 'hide':
							datetimepicker.trigger('close.xdsoft');
						break;
						case 'destroy':
							destroyDateTimePicker($(this));
						break;
						case 'reset':
							this.value = this.defaultValue;
							if(!this.value || !datetimepicker.data('xdsoft_datetime').isValidDate(Date.parseDate(this.value, options.format)))
								datetimepicker.data('changed',false);
							datetimepicker.data('xdsoft_datetime').setCurrentTime(this.value);
						break;
					}
				}else{
					datetimepicker
						.setOptions(opt);
				}
				return 0;
			}else
				if( ($.type(opt) !== 'string') ){
					if( !options.lazyInit||options.open||options.inline ){
						createDateTimePicker($(this));
					}else
						lazyInit($(this));
				}
		});
	};
	$.fn.datetimepicker.defaults = default_options;
})( jQuery );

/*
 * Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net)
 *
 * Licensed under the MIT License (LICENSE.txt).
 *
 * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
 * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
 * Thanks to: Seamus Leahy for adding deltaX and deltaY
 *
 * Version: 3.1.3
 *
 * Requires: 1.2.2+
 */
(function(factory) {if(typeof define==='function'&&define.amd) {define(['jquery'],factory)}else if(typeof exports==='object') {module.exports=factory}else{factory(jQuery)}}(function($) {var toFix=['wheel','mousewheel','DOMMouseScroll','MozMousePixelScroll'];var toBind='onwheel'in document||document.documentMode>=9?['wheel']:['mousewheel','DomMouseScroll','MozMousePixelScroll'];var lowestDelta,lowestDeltaXY;if($.event.fixHooks) {for(var i=toFix.length;i;) {$.event.fixHooks[toFix[--i]]=$.event.mouseHooks}}$.event.special.mousewheel={setup:function() {if(this.addEventListener) {for(var i=toBind.length;i;) {this.addEventListener(toBind[--i],handler,false)}}else{this.onmousewheel=handler}},teardown:function() {if(this.removeEventListener) {for(var i=toBind.length;i;) {this.removeEventListener(toBind[--i],handler,false)}}else{this.onmousewheel=null}}};$.fn.extend({mousewheel:function(fn) {return fn?this.bind("mousewheel",fn):this.trigger("mousewheel")},unmousewheel:function(fn) {return this.unbind("mousewheel",fn)}});function handler(event) {var orgEvent=event||window.event,args=[].slice.call(arguments,1),delta=0,deltaX=0,deltaY=0,absDelta=0,absDeltaXY=0,fn;event=$.event.fix(orgEvent);event.type="mousewheel";if(orgEvent.wheelDelta) {delta=orgEvent.wheelDelta}if(orgEvent.detail) {delta=orgEvent.detail*-1}if(orgEvent.deltaY) {deltaY=orgEvent.deltaY*-1;delta=deltaY}if(orgEvent.deltaX) {deltaX=orgEvent.deltaX;delta=deltaX*-1}if(orgEvent.wheelDeltaY!==undefined) {deltaY=orgEvent.wheelDeltaY}if(orgEvent.wheelDeltaX!==undefined) {deltaX=orgEvent.wheelDeltaX*-1}absDelta=Math.abs(delta);if(!lowestDelta||absDelta<lowestDelta) {lowestDelta=absDelta}absDeltaXY=Math.max(Math.abs(deltaY),Math.abs(deltaX));if(!lowestDeltaXY||absDeltaXY<lowestDeltaXY) {lowestDeltaXY=absDeltaXY}fn=delta>0?'floor':'ceil';delta=Math[fn](delta/lowestDelta);deltaX=Math[fn](deltaX/lowestDeltaXY);deltaY=Math[fn](deltaY/lowestDeltaXY);args.unshift(event,delta,deltaX,deltaY);return($.event.dispatch||$.event.handle).apply(this,args)}}));


// Parse and Format Library
//http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
/*
 * Copyright (C) 2004 Baron Schwartz <baron at sequent dot org>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by the
 * Free Software Foundation, version 2.1.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 * details.
 */
Date.parseFunctions={count:0};Date.parseRegexes=[];Date.formatFunctions={count:0};Date.prototype.dateFormat=function(b){if(b=="unixtime"){return parseInt(this.getTime()/1000);}if(Date.formatFunctions[b]==null){Date.createNewFormat(b);}var a=Date.formatFunctions[b];return this[a]();};Date.createNewFormat=function(format){var funcName="format"+Date.formatFunctions.count++;Date.formatFunctions[format]=funcName;var code="Date.prototype."+funcName+" = function() {return ";var special=false;var ch="";for(var i=0;i<format.length;++i){ch=format.charAt(i);if(!special&&ch=="\\"){special=true;}else{if(special){special=false;code+="'"+String.escape(ch)+"' + ";}else{code+=Date.getFormatCode(ch);}}}eval(code.substring(0,code.length-3)+";}");};Date.getFormatCode=function(a){switch(a){case"d":return"String.leftPad(this.getDate(), 2, '0') + ";case"D":return"Date.dayNames[this.getDay()].substring(0, 3) + ";case"j":return"this.getDate() + ";case"l":return"Date.dayNames[this.getDay()] + ";case"S":return"this.getSuffix() + ";case"w":return"this.getDay() + ";case"z":return"this.getDayOfYear() + ";case"W":return"this.getWeekOfYear() + ";case"F":return"Date.monthNames[this.getMonth()] + ";case"m":return"String.leftPad(this.getMonth() + 1, 2, '0') + ";case"M":return"Date.monthNames[this.getMonth()].substring(0, 3) + ";case"n":return"(this.getMonth() + 1) + ";case"t":return"this.getDaysInMonth() + ";case"L":return"(this.isLeapYear() ? 1 : 0) + ";case"Y":return"this.getFullYear() + ";case"y":return"('' + this.getFullYear()).substring(2, 4) + ";case"a":return"(this.getHours() < 12 ? 'am' : 'pm') + ";case"A":return"(this.getHours() < 12 ? 'AM' : 'PM') + ";case"g":return"((this.getHours() %12) ? this.getHours() % 12 : 12) + ";case"G":return"this.getHours() + ";case"h":return"String.leftPad((this.getHours() %12) ? this.getHours() % 12 : 12, 2, '0') + ";case"H":return"String.leftPad(this.getHours(), 2, '0') + ";case"i":return"String.leftPad(this.getMinutes(), 2, '0') + ";case"s":return"String.leftPad(this.getSeconds(), 2, '0') + ";case"O":return"this.getGMTOffset() + ";case"T":return"this.getTimezone() + ";case"Z":return"(this.getTimezoneOffset() * -60) + ";default:return"'"+String.escape(a)+"' + ";}};Date.parseDate=function(a,c){if(c=="unixtime"){return new Date(!isNaN(parseInt(a))?parseInt(a)*1000:0);}if(Date.parseFunctions[c]==null){Date.createParser(c);}var b=Date.parseFunctions[c];return Date[b](a);};Date.createParser=function(format){var funcName="parse"+Date.parseFunctions.count++;var regexNum=Date.parseRegexes.length;var currentGroup=1;Date.parseFunctions[format]=funcName;var code="Date."+funcName+" = function(input) {\nvar y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, z = -1;\nvar d = new Date();\ny = d.getFullYear();\nm = d.getMonth();\nd = d.getDate();\nvar results = input.match(Date.parseRegexes["+regexNum+"]);\nif (results && results.length > 0) {";var regex="";var special=false;var ch="";for(var i=0;i<format.length;++i){ch=format.charAt(i);if(!special&&ch=="\\"){special=true;}else{if(special){special=false;regex+=String.escape(ch);}else{obj=Date.formatCodeToRegex(ch,currentGroup);currentGroup+=obj.g;regex+=obj.s;if(obj.g&&obj.c){code+=obj.c;}}}}code+="if (y > 0 && z > 0){\nvar doyDate = new Date(y,0);\ndoyDate.setDate(z);\nm = doyDate.getMonth();\nd = doyDate.getDate();\n}";code+="if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n{return new Date(y, m, d, h, i, s);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n{return new Date(y, m, d, h, i);}\nelse if (y > 0 && m >= 0 && d > 0 && h >= 0)\n{return new Date(y, m, d, h);}\nelse if (y > 0 && m >= 0 && d > 0)\n{return new Date(y, m, d);}\nelse if (y > 0 && m >= 0)\n{return new Date(y, m);}\nelse if (y > 0)\n{return new Date(y);}\n}return null;}";Date.parseRegexes[regexNum]=new RegExp("^"+regex+"$");eval(code);};Date.formatCodeToRegex=function(b,a){switch(b){case"D":return{g:0,c:null,s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};case"j":case"d":return{g:1,c:"d = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"l":return{g:0,c:null,s:"(?:"+Date.dayNames.join("|")+")"};case"S":return{g:0,c:null,s:"(?:st|nd|rd|th)"};case"w":return{g:0,c:null,s:"\\d"};case"z":return{g:1,c:"z = parseInt(results["+a+"], 10);\n",s:"(\\d{1,3})"};case"W":return{g:0,c:null,s:"(?:\\d{2})"};case"F":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"].substring(0, 3)], 10);\n",s:"("+Date.monthNames.join("|")+")"};case"M":return{g:1,c:"m = parseInt(Date.monthNumbers[results["+a+"]], 10);\n",s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};case"n":case"m":return{g:1,c:"m = parseInt(results["+a+"], 10) - 1;\n",s:"(\\d{1,2})"};case"t":return{g:0,c:null,s:"\\d{1,2}"};case"L":return{g:0,c:null,s:"(?:1|0)"};case"Y":return{g:1,c:"y = parseInt(results["+a+"], 10);\n",s:"(\\d{4})"};case"y":return{g:1,c:"var ty = parseInt(results["+a+"], 10);\ny = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",s:"(\\d{1,2})"};case"a":return{g:1,c:"if (results["+a+"] == 'am') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(am|pm)"};case"A":return{g:1,c:"if (results["+a+"] == 'AM') {\nif (h == 12) { h = 0; }\n} else { if (h < 12) { h += 12; }}",s:"(AM|PM)"};case"g":case"G":case"h":case"H":return{g:1,c:"h = parseInt(results["+a+"], 10);\n",s:"(\\d{1,2})"};case"i":return{g:1,c:"i = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"s":return{g:1,c:"s = parseInt(results["+a+"], 10);\n",s:"(\\d{2})"};case"O":return{g:0,c:null,s:"[+-]\\d{4}"};case"T":return{g:0,c:null,s:"[A-Z]{3}"};case"Z":return{g:0,c:null,s:"[+-]\\d{1,5}"};default:return{g:0,c:null,s:String.escape(b)};}};Date.prototype.getTimezone=function(){return this.toString().replace(/^.*? ([A-Z]{3}) [0-9]{4}.*$/,"$1").replace(/^.*?\(([A-Z])[a-z]+ ([A-Z])[a-z]+ ([A-Z])[a-z]+\)$/,"$1$2$3");};Date.prototype.getGMTOffset=function(){return(this.getTimezoneOffset()>0?"-":"+")+String.leftPad(Math.floor(Math.abs(this.getTimezoneOffset())/60),2,"0")+String.leftPad(Math.abs(this.getTimezoneOffset())%60,2,"0");};Date.prototype.getDayOfYear=function(){var a=0;Date.daysInMonth[1]=this.isLeapYear()?29:28;for(var b=0;b<this.getMonth();++b){a+=Date.daysInMonth[b];}return a+this.getDate();};Date.prototype.getWeekOfYear=function(){var b=this.getDayOfYear()+(4-this.getDay());var a=new Date(this.getFullYear(),0,1);var c=(7-a.getDay()+4);return String.leftPad(Math.ceil((b-c)/7)+1,2,"0");};Date.prototype.isLeapYear=function(){var a=this.getFullYear();return((a&3)==0&&(a%100||(a%400==0&&a)));};Date.prototype.getFirstDayOfMonth=function(){var a=(this.getDay()-(this.getDate()-1))%7;return(a<0)?(a+7):a;};Date.prototype.getLastDayOfMonth=function(){var a=(this.getDay()+(Date.daysInMonth[this.getMonth()]-this.getDate()))%7;return(a<0)?(a+7):a;};Date.prototype.getDaysInMonth=function(){Date.daysInMonth[1]=this.isLeapYear()?29:28;return Date.daysInMonth[this.getMonth()];};Date.prototype.getSuffix=function(){switch(this.getDate()){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};String.escape=function(a){return a.replace(/('|\\)/g,"\\$1");};String.leftPad=function(d,b,c){var a=new String(d);if(c==null){c=" ";}while(a.length<b){a=c+a;}return a;};Date.daysInMonth=[31,28,31,30,31,30,31,31,30,31,30,31];Date.monthNames=["January","February","March","April","May","June","July","August","September","October","November","December"];Date.dayNames=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];Date.y2kYear=50;Date.monthNumbers={Jan:0,Feb:1,Mar:2,Apr:3,May:4,Jun:5,Jul:6,Aug:7,Sep:8,Oct:9,Nov:10,Dec:11};Date.patterns={ISO8601LongPattern:"Y-m-d H:i:s",ISO8601ShortPattern:"Y-m-d",ShortDatePattern:"n/j/Y",LongDatePattern:"l, F d, Y",FullDateTimePattern:"l, F d, Y g:i:s A",MonthDayPattern:"F d",ShortTimePattern:"g:i A",LongTimePattern:"g:i:s A",SortableDateTimePattern:"Y-m-d\\TH:i:s",UniversalSortableDateTimePattern:"Y-m-d H:i:sO",YearMonthPattern:"F, Y"};
;
/*!
* jquery.inputmask.bundle.js
* http://github.com/RobinHerbots/jquery.inputmask
* Copyright (c) 2010 - 2015 Robin Herbots
* Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php)
* Version: 3.2.1-55
*/
!function ($) {
    function Inputmask(options) {
        this.el = void 0, this.opts = $.extend(!0, {}, this.defaults, options), this.noMasksCache = options && void 0 !== options.definitions,
        this.userOptions = options || {}, resolveAlias(this.opts.alias, options, this.opts);
    }
    function isInputEventSupported(eventName) {
        var el = document.createElement("input"), evName = "on" + eventName, isSupported = evName in el;
        return isSupported || (el.setAttribute(evName, "return;"), isSupported = "function" == typeof el[evName]),
        el = null, isSupported;
    }
    function isInputTypeSupported(inputType) {
        var isSupported = "text" === inputType || "tel" === inputType || "password" === inputType;
        if (!isSupported) {
            var el = document.createElement("input");
            el.setAttribute("type", inputType), isSupported = "text" === el.type, el = null;
        }
        return isSupported;
    }
    function resolveAlias(aliasStr, options, opts) {
        var aliasDefinition = opts.aliases[aliasStr];
        return aliasDefinition ? (aliasDefinition.alias && resolveAlias(aliasDefinition.alias, void 0, opts),
        $.extend(!0, opts, aliasDefinition), $.extend(!0, opts, options), !0) : (null === opts.mask && (opts.mask = aliasStr),
        !1);
    }
    function importAttributeOptions(npt, opts, userOptions) {
        function importOption(option) {
            var optionData = npt.getAttribute("data-inputmask-" + option.toLowerCase());
            null !== optionData && (optionData = "boolean" == typeof optionData ? optionData : optionData.toString(),
            "string" == typeof optionData && 0 === option.indexOf("on") && (optionData = eval("(" + optionData + ")")),
            "mask" === option && 0 === optionData.indexOf("[") ? (userOptions[option] = optionData.replace(/[\s[\]]/g, "").split(","),
            userOptions[option][0] = userOptions[option][0].replace("'", ""), userOptions[option][userOptions[option].length - 1] = userOptions[option][userOptions[option].length - 1].replace("'", "")) : userOptions[option] = optionData);
        }
        var attrOptions = npt.getAttribute("data-inputmask");
        if (attrOptions && "" !== attrOptions) try {
            attrOptions = attrOptions.replace(new RegExp("'", "g"), '"');
            var dataoptions = $.parseJSON("{" + attrOptions + "}");
            $.extend(!0, userOptions, dataoptions);
        } catch (ex) { }
        for (var option in opts) importOption(option);
        if (userOptions.alias) {
            resolveAlias(userOptions.alias, userOptions, opts);
            for (option in opts) importOption(option);
        }
        return $.extend(!0, opts, userOptions), opts;
    }
    function generateMaskSet(opts, nocache) {
        function analyseMask(mask) {
            function MaskToken(isGroup, isOptional, isQuantifier, isAlternator) {
                this.matches = [], this.isGroup = isGroup || !1, this.isOptional = isOptional || !1,
                this.isQuantifier = isQuantifier || !1, this.isAlternator = isAlternator || !1,
                this.quantifier = {
                    min: 1,
                    max: 1
                };
            }
            function insertTestDefinition(mtoken, element, position) {
                var maskdef = opts.definitions[element];
                position = void 0 !== position ? position : mtoken.matches.length;
                var prevMatch = mtoken.matches[position - 1];
                if (maskdef && !escaped) {
                    maskdef.placeholder = $.isFunction(maskdef.placeholder) ? maskdef.placeholder.call(this, opts) : maskdef.placeholder;
                    for (var prevalidators = maskdef.prevalidator, prevalidatorsL = prevalidators ? prevalidators.length : 0, i = 1; i < maskdef.cardinality; i++) {
                        var prevalidator = prevalidatorsL >= i ? prevalidators[i - 1] : [], validator = prevalidator.validator, cardinality = prevalidator.cardinality;
                        mtoken.matches.splice(position++, 0, {
                            fn: validator ? "string" == typeof validator ? new RegExp(validator) : new function () {
                                this.test = validator;
                            }() : new RegExp("."),
                            cardinality: cardinality ? cardinality : 1,
                            optionality: mtoken.isOptional,
                            newBlockMarker: void 0 === prevMatch || prevMatch.def !== (maskdef.definitionSymbol || element),
                            casing: maskdef.casing,
                            def: maskdef.definitionSymbol || element,
                            placeholder: maskdef.placeholder,
                            mask: element
                        }), prevMatch = mtoken.matches[position - 1];
                    }
                    mtoken.matches.splice(position++, 0, {
                        fn: maskdef.validator ? "string" == typeof maskdef.validator ? new RegExp(maskdef.validator) : new function () {
                            this.test = maskdef.validator;
                        }() : new RegExp("."),
                        cardinality: maskdef.cardinality,
                        optionality: mtoken.isOptional,
                        newBlockMarker: void 0 === prevMatch || prevMatch.def !== (maskdef.definitionSymbol || element),
                        casing: maskdef.casing,
                        def: maskdef.definitionSymbol || element,
                        placeholder: maskdef.placeholder,
                        mask: element
                    });
                } else mtoken.matches.splice(position++, 0, {
                    fn: null,
                    cardinality: 0,
                    optionality: mtoken.isOptional,
                    newBlockMarker: void 0 === prevMatch || prevMatch.def !== element,
                    casing: null,
                    def: element,
                    placeholder: void 0,
                    mask: element
                }), escaped = !1;
            }
            function verifyGroupMarker(lastMatch, isOpenGroup) {
                lastMatch.isGroup && (lastMatch.isGroup = !1, insertTestDefinition(lastMatch, opts.groupmarker.start, 0),
                isOpenGroup !== !0 && insertTestDefinition(lastMatch, opts.groupmarker.end));
            }
            function maskCurrentToken(m, currentToken, lastMatch, extraCondition) {
                currentToken.matches.length > 0 && (void 0 === extraCondition || extraCondition) && (lastMatch = currentToken.matches[currentToken.matches.length - 1],
                verifyGroupMarker(lastMatch)), insertTestDefinition(currentToken, m);
            }
            function defaultCase() {
                if (openenings.length > 0) {
                    if (currentOpeningToken = openenings[openenings.length - 1], maskCurrentToken(m, currentOpeningToken, lastMatch, !currentOpeningToken.isAlternator),
                    currentOpeningToken.isAlternator) {
                        alternator = openenings.pop();
                        for (var mndx = 0; mndx < alternator.matches.length; mndx++) alternator.matches[mndx].isGroup = !1;
                        openenings.length > 0 ? (currentOpeningToken = openenings[openenings.length - 1],
                        currentOpeningToken.matches.push(alternator)) : currentToken.matches.push(alternator);
                    }
                } else maskCurrentToken(m, currentToken, lastMatch);
            }
            function reverseTokens(maskToken) {
                function reverseStatic(st) {
                    return st === opts.optionalmarker.start ? st = opts.optionalmarker.end : st === opts.optionalmarker.end ? st = opts.optionalmarker.start : st === opts.groupmarker.start ? st = opts.groupmarker.end : st === opts.groupmarker.end && (st = opts.groupmarker.start),
                    st;
                }
                maskToken.matches = maskToken.matches.reverse();
                for (var match in maskToken.matches) {
                    var intMatch = parseInt(match);
                    if (maskToken.matches[match].isQuantifier && maskToken.matches[intMatch + 1] && maskToken.matches[intMatch + 1].isGroup) {
                        var qt = maskToken.matches[match];
                        maskToken.matches.splice(match, 1), maskToken.matches.splice(intMatch + 1, 0, qt);
                    }
                    void 0 !== maskToken.matches[match].matches ? maskToken.matches[match] = reverseTokens(maskToken.matches[match]) : maskToken.matches[match] = reverseStatic(maskToken.matches[match]);
                }
                return maskToken;
            }
            for (var match, m, openingToken, currentOpeningToken, alternator, lastMatch, groupToken, tokenizer = /(?:[?*+]|\{[0-9\+\*]+(?:,[0-9\+\*]*)?\})|[^.?*+^${[]()|\\]+|./g, escaped = !1, currentToken = new MaskToken(), openenings = [], maskTokens = []; match = tokenizer.exec(mask) ;) if (m = match[0],
            escaped) defaultCase(); else switch (m.charAt(0)) {
                case opts.escapeChar:
                    escaped = !0;
                    break;

                case opts.optionalmarker.end:
                case opts.groupmarker.end:
                    if (openingToken = openenings.pop(), void 0 !== openingToken) if (openenings.length > 0) {
                        if (currentOpeningToken = openenings[openenings.length - 1], currentOpeningToken.matches.push(openingToken),
                        currentOpeningToken.isAlternator) {
                            alternator = openenings.pop();
                            for (var mndx = 0; mndx < alternator.matches.length; mndx++) alternator.matches[mndx].isGroup = !1;
                            openenings.length > 0 ? (currentOpeningToken = openenings[openenings.length - 1],
                            currentOpeningToken.matches.push(alternator)) : currentToken.matches.push(alternator);
                        }
                    } else currentToken.matches.push(openingToken); else defaultCase();
                    break;

                case opts.optionalmarker.start:
                    openenings.push(new MaskToken(!1, !0));
                    break;

                case opts.groupmarker.start:
                    openenings.push(new MaskToken(!0));
                    break;

                case opts.quantifiermarker.start:
                    var quantifier = new MaskToken(!1, !1, !0);
                    m = m.replace(/[{}]/g, "");
                    var mq = m.split(","), mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]), mq1 = 1 === mq.length ? mq0 : isNaN(mq[1]) ? mq[1] : parseInt(mq[1]);
                    if (("*" === mq1 || "+" === mq1) && (mq0 = "*" === mq1 ? 0 : 1), quantifier.quantifier = {
                        min: mq0,
                        max: mq1
                    }, openenings.length > 0) {
                        var matches = openenings[openenings.length - 1].matches;
                        match = matches.pop(), match.isGroup || (groupToken = new MaskToken(!0), groupToken.matches.push(match),
                        match = groupToken), matches.push(match), matches.push(quantifier);
                    } else match = currentToken.matches.pop(), match.isGroup || (groupToken = new MaskToken(!0),
                    groupToken.matches.push(match), match = groupToken), currentToken.matches.push(match),
                    currentToken.matches.push(quantifier);
                    break;

                case opts.alternatormarker:
                    openenings.length > 0 ? (currentOpeningToken = openenings[openenings.length - 1],
                    lastMatch = currentOpeningToken.matches.pop()) : lastMatch = currentToken.matches.pop(),
                    lastMatch.isAlternator ? openenings.push(lastMatch) : (alternator = new MaskToken(!1, !1, !1, !0),
                    alternator.matches.push(lastMatch), openenings.push(alternator));
                    break;

                default:
                    defaultCase();
            }
            for (; openenings.length > 0;) openingToken = openenings.pop(), verifyGroupMarker(openingToken, !0),
            currentToken.matches.push(openingToken);
            return currentToken.matches.length > 0 && (lastMatch = currentToken.matches[currentToken.matches.length - 1],
            verifyGroupMarker(lastMatch), maskTokens.push(currentToken)), opts.numericInput && reverseTokens(maskTokens[0]),
            maskTokens;
        }
        function generateMask(mask, metadata) {
            if (null === mask || "" === mask) return void 0;
            if (1 === mask.length && opts.greedy === !1 && 0 !== opts.repeat && (opts.placeholder = ""),
            opts.repeat > 0 || "*" === opts.repeat || "+" === opts.repeat) {
                var repeatStart = "*" === opts.repeat ? 0 : "+" === opts.repeat ? 1 : opts.repeat;
                mask = opts.groupmarker.start + mask + opts.groupmarker.end + opts.quantifiermarker.start + repeatStart + "," + opts.repeat + opts.quantifiermarker.end;
            }
            var masksetDefinition;
            return void 0 === Inputmask.prototype.masksCache[mask] || nocache === !0 ? (masksetDefinition = {
                mask: mask,
                maskToken: analyseMask(mask),
                validPositions: {},
                _buffer: void 0,
                buffer: void 0,
                tests: {},
                metadata: metadata
            }, nocache !== !0 && (Inputmask.prototype.masksCache[opts.numericInput ? mask.split("").reverse().join("") : mask] = masksetDefinition)) : masksetDefinition = $.extend(!0, {}, Inputmask.prototype.masksCache[mask]),
            masksetDefinition;
        }
        function preProcessMask(mask) {
            return mask = mask.toString();
        }
        var ms;
        if ($.isFunction(opts.mask) && (opts.mask = opts.mask.call(this, opts)), $.isArray(opts.mask)) {
            if (opts.mask.length > 1) {
                opts.keepStatic = null === opts.keepStatic ? !0 : opts.keepStatic;
                var altMask = "(";
                return $.each(opts.numericInput ? opts.mask.reverse() : opts.mask, function (ndx, msk) {
                    altMask.length > 1 && (altMask += ")|("), altMask += preProcessMask(void 0 === msk.mask || $.isFunction(msk.mask) ? msk : msk.mask);
                }), altMask += ")", generateMask(altMask, opts.mask);
            }
            opts.mask = opts.mask.pop();
        }
        return opts.mask && (ms = void 0 === opts.mask.mask || $.isFunction(opts.mask.mask) ? generateMask(preProcessMask(opts.mask), opts.mask) : generateMask(preProcessMask(opts.mask.mask), opts.mask)),
        ms;
    }
    function maskScope(actionObj, maskset, opts) {
        function getMaskTemplate(baseOnInput, minimalPos, includeInput) {
            minimalPos = minimalPos || 0;
            var ndxIntlzr, test, testPos, maskTemplate = [], pos = 0;
            do {
                if (baseOnInput === !0 && getMaskSet().validPositions[pos]) {
                    var validPos = getMaskSet().validPositions[pos];
                    test = validPos.match, ndxIntlzr = validPos.locator.slice(), maskTemplate.push(includeInput === !0 ? validPos.input : getPlaceholder(pos, test));
                } else testPos = getTestTemplate(pos, ndxIntlzr, pos - 1), test = testPos.match,
                ndxIntlzr = testPos.locator.slice(), maskTemplate.push(getPlaceholder(pos, test));
                pos++;
            } while ((void 0 === maxLength || maxLength > pos - 1) && null !== test.fn || null === test.fn && "" !== test.def || minimalPos >= pos);
            return maskTemplate.pop(), maskTemplate;
        }
        function getMaskSet() {
            return maskset;
        }
        function resetMaskSet(soft) {
            var maskset = getMaskSet();
            maskset.buffer = void 0, maskset.tests = {}, soft !== !0 && (maskset._buffer = void 0,
            maskset.validPositions = {}, maskset.p = 0);
        }
        function getLastValidPosition(closestTo, strict) {
            var maskset = getMaskSet(), lastValidPosition = -1, valids = maskset.validPositions;
            void 0 === closestTo && (closestTo = -1);
            var before = lastValidPosition, after = lastValidPosition;
            for (var posNdx in valids) {
                var psNdx = parseInt(posNdx);
                valids[psNdx] && (strict || null !== valids[psNdx].match.fn) && (closestTo >= psNdx && (before = psNdx),
                psNdx >= closestTo && (after = psNdx));
            }
            return lastValidPosition = -1 !== before && closestTo - before > 1 || closestTo > after ? before : after;
        }
        function setValidPosition(pos, validTest, fromSetValid) {
            if (opts.insertMode && void 0 !== getMaskSet().validPositions[pos] && void 0 === fromSetValid) {
                var i, positionsClone = $.extend(!0, {}, getMaskSet().validPositions), lvp = getLastValidPosition();
                for (i = pos; lvp >= i; i++) delete getMaskSet().validPositions[i];
                getMaskSet().validPositions[pos] = validTest;
                var j, valid = !0, vps = getMaskSet().validPositions;
                for (i = j = pos; lvp >= i; i++) {
                    var t = positionsClone[i];
                    if (void 0 !== t) for (var posMatch = j, prevPosMatch = -1; posMatch < getMaskLength() && (null == t.match.fn && vps[i] && (vps[i].match.optionalQuantifier === !0 || vps[i].match.optionality === !0) || null != t.match.fn) ;) {
                        if (null === t.match.fn || !opts.keepStatic && vps[i] && (void 0 !== vps[i + 1] && getTests(i + 1, vps[i].locator.slice(), i).length > 1 || void 0 !== vps[i].alternation) ? posMatch++ : posMatch = seekNext(j),
                        positionCanMatchDefinition(posMatch, t.match.def)) {
                            valid = isValid(posMatch, t.input, !0, !0) !== !1, j = posMatch;
                            break;
                        }
                        if (valid = null == t.match.fn, prevPosMatch === posMatch) break;
                        prevPosMatch = posMatch;
                    }
                    if (!valid) break;
                }
                if (!valid) return getMaskSet().validPositions = $.extend(!0, {}, positionsClone),
                !1;
            } else getMaskSet().validPositions[pos] = validTest;
            return !0;
        }
        function stripValidPositions(start, end, nocheck, strict) {
            var i, startPos = start;
            for (getMaskSet().p = start, i = startPos; end > i; i++) void 0 !== getMaskSet().validPositions[i] && (nocheck === !0 || opts.canClearPosition(getMaskSet(), i, getLastValidPosition(), strict, opts) !== !1) && delete getMaskSet().validPositions[i];
            for (resetMaskSet(!0), i = startPos + 1; i <= getLastValidPosition() ;) {
                for (; void 0 !== getMaskSet().validPositions[startPos];) startPos++;
                var s = getMaskSet().validPositions[startPos];
                startPos > i && (i = startPos + 1);
                var t = getMaskSet().validPositions[i];
                void 0 !== t && isMask(i) && void 0 === s ? (positionCanMatchDefinition(startPos, t.match.def) && isValid(startPos, t.input, !0) !== !1 && (delete getMaskSet().validPositions[i],
                i++), startPos++) : i++;
            }
            var lvp = getLastValidPosition(), ml = getMaskLength();
            for (strict !== !0 && nocheck !== !0 && void 0 !== getMaskSet().validPositions[lvp] && getMaskSet().validPositions[lvp].input === opts.radixPoint && delete getMaskSet().validPositions[lvp],
            i = lvp + 1; ml >= i; i++) getMaskSet().validPositions[i] && delete getMaskSet().validPositions[i];
            resetMaskSet(!0);
        }
        function getTestTemplate(pos, ndxIntlzr, tstPs) {
            var testPos = getMaskSet().validPositions[pos];
            if (void 0 === testPos) for (var testPositions = getTests(pos, ndxIntlzr, tstPs), lvp = getLastValidPosition(), lvTest = getMaskSet().validPositions[lvp] || getTests(0)[0], lvTestAltArr = void 0 !== lvTest.alternation ? lvTest.locator[lvTest.alternation].toString().split(",") : [], ndx = 0; ndx < testPositions.length && (testPos = testPositions[ndx],
            !(testPos.match && (opts.greedy && testPos.match.optionalQuantifier !== !0 || (testPos.match.optionality === !1 || testPos.match.newBlockMarker === !1) && testPos.match.optionalQuantifier !== !0) && (void 0 === lvTest.alternation || lvTest.alternation !== testPos.alternation || void 0 !== testPos.locator[lvTest.alternation] && checkAlternationMatch(testPos.locator[lvTest.alternation].toString().split(","), lvTestAltArr)))) ; ndx++);
            return testPos;
        }
        function getTest(pos) {
            return getMaskSet().validPositions[pos] ? getMaskSet().validPositions[pos].match : getTests(pos)[0].match;
        }
        function positionCanMatchDefinition(pos, def) {
            for (var valid = !1, tests = getTests(pos), tndx = 0; tndx < tests.length; tndx++) if (tests[tndx].match && tests[tndx].match.def === def) {
                valid = !0;
                break;
            }
            return valid;
        }
        function getTests(pos, ndxIntlzr, tstPs, cacheable) {
            function resolveTestFromToken(maskToken, ndxInitializer, loopNdx, quantifierRecurse) {
                function handleMatch(match, loopNdx, quantifierRecurse) {
                    if (testPos > 1e4) throw "Inputmask: There is probably an error in your mask definition or in the code. Create an issue on github with an example of the mask you are using. " + getMaskSet().mask;
                    if (testPos === pos && void 0 === match.matches) return matches.push({
                        match: match,
                        locator: loopNdx.reverse()
                    }), !0;
                    if (void 0 !== match.matches) {
                        if (match.isGroup && quantifierRecurse !== match) {
                            if (match = handleMatch(maskToken.matches[$.inArray(match, maskToken.matches) + 1], loopNdx)) return !0;
                        } else if (match.isOptional) {
                            var optionalToken = match;
                            if (match = resolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse)) {
                                if (latestMatch = matches[matches.length - 1].match, isFirstMatch = 0 === $.inArray(latestMatch, optionalToken.matches),
                                !isFirstMatch) return !0;
                                insertStop = !0, testPos = pos;
                            }
                        } else if (match.isAlternator) {
                            var maltMatches, alternateToken = match, malternateMatches = [], currentMatches = matches.slice(), loopNdxCnt = loopNdx.length, altIndex = ndxInitializer.length > 0 ? ndxInitializer.shift() : -1;
                            if (-1 === altIndex || "string" == typeof altIndex) {
                                var currentPos = testPos, ndxInitializerClone = ndxInitializer.slice(), altIndexArr = [];
                                "string" == typeof altIndex && (altIndexArr = altIndex.split(","));
                                for (var amndx = 0; amndx < alternateToken.matches.length; amndx++) {
                                    if (matches = [], match = handleMatch(alternateToken.matches[amndx], [amndx].concat(loopNdx), quantifierRecurse) || match,
                                    match !== !0 && void 0 !== match && altIndexArr[altIndexArr.length - 1] < alternateToken.matches.length) {
                                        var ntndx = maskToken.matches.indexOf(match) + 1;
                                        maskToken.matches.length > ntndx && (match = handleMatch(maskToken.matches[ntndx], [ntndx].concat(loopNdx.slice(1, loopNdx.length)), quantifierRecurse),
                                        match && (altIndexArr.push(ntndx.toString()), $.each(matches, function (ndx, lmnt) {
                                            lmnt.alternation = loopNdx.length - 1;
                                        })));
                                    }
                                    maltMatches = matches.slice(), testPos = currentPos, matches = [];
                                    for (var i = 0; i < ndxInitializerClone.length; i++) ndxInitializer[i] = ndxInitializerClone[i];
                                    for (var ndx1 = 0; ndx1 < maltMatches.length; ndx1++) {
                                        var altMatch = maltMatches[ndx1];
                                        altMatch.alternation = altMatch.alternation || loopNdxCnt;
                                        for (var ndx2 = 0; ndx2 < malternateMatches.length; ndx2++) {
                                            var altMatch2 = malternateMatches[ndx2];
                                            if (altMatch.match.mask === altMatch2.match.mask && ("string" != typeof altIndex || -1 !== $.inArray(altMatch.locator[altMatch.alternation].toString(), altIndexArr))) {
                                                maltMatches.splice(ndx1, 1), ndx1--, altMatch2.locator[altMatch.alternation] = altMatch2.locator[altMatch.alternation] + "," + altMatch.locator[altMatch.alternation],
                                                altMatch2.alternation = altMatch.alternation;
                                                break;
                                            }
                                        }
                                    }
                                    malternateMatches = malternateMatches.concat(maltMatches);
                                }
                                "string" == typeof altIndex && (malternateMatches = $.map(malternateMatches, function (lmnt, ndx) {
                                    if (isFinite(ndx)) {
                                        var mamatch, alternation = lmnt.alternation, altLocArr = lmnt.locator[alternation].toString().split(",");
                                        lmnt.locator[alternation] = void 0, lmnt.alternation = void 0;
                                        for (var alndx = 0; alndx < altLocArr.length; alndx++) mamatch = -1 !== $.inArray(altLocArr[alndx], altIndexArr),
                                        mamatch && (void 0 !== lmnt.locator[alternation] ? (lmnt.locator[alternation] += ",",
                                        lmnt.locator[alternation] += altLocArr[alndx]) : lmnt.locator[alternation] = parseInt(altLocArr[alndx]),
                                        lmnt.alternation = alternation);
                                        if (void 0 !== lmnt.locator[alternation]) return lmnt;
                                    }
                                })), matches = currentMatches.concat(malternateMatches), testPos = pos, insertStop = matches.length > 0;
                            } else match = alternateToken.matches[altIndex] ? handleMatch(alternateToken.matches[altIndex], [altIndex].concat(loopNdx), quantifierRecurse) : !1;
                            if (match) return !0;
                        } else if (match.isQuantifier && quantifierRecurse !== maskToken.matches[$.inArray(match, maskToken.matches) - 1]) for (var qt = match, qndx = ndxInitializer.length > 0 ? ndxInitializer.shift() : 0; qndx < (isNaN(qt.quantifier.max) ? qndx + 1 : qt.quantifier.max) && pos >= testPos; qndx++) {
                            var tokenGroup = maskToken.matches[$.inArray(qt, maskToken.matches) - 1];
                            if (match = handleMatch(tokenGroup, [qndx].concat(loopNdx), tokenGroup)) {
                                if (latestMatch = matches[matches.length - 1].match, latestMatch.optionalQuantifier = qndx > qt.quantifier.min - 1,
                                isFirstMatch = 0 === $.inArray(latestMatch, tokenGroup.matches)) {
                                    if (qndx > qt.quantifier.min - 1) {
                                        insertStop = !0, testPos = pos;
                                        break;
                                    }
                                    return !0;
                                }
                                return !0;
                            }
                        } else if (match = resolveTestFromToken(match, ndxInitializer, loopNdx, quantifierRecurse)) return !0;
                    } else testPos++;
                }
                for (var tndx = ndxInitializer.length > 0 ? ndxInitializer.shift() : 0; tndx < maskToken.matches.length; tndx++) if (maskToken.matches[tndx].isQuantifier !== !0) {
                    var match = handleMatch(maskToken.matches[tndx], [tndx].concat(loopNdx), quantifierRecurse);
                    if (match && testPos === pos) return match;
                    if (testPos > pos) break;
                }
            }
            var latestMatch, isFirstMatch, maskTokens = getMaskSet().maskToken, testPos = ndxIntlzr ? tstPs : 0, ndxInitializer = ndxIntlzr || [0], matches = [], insertStop = !1;
            if (cacheable === !0 && getMaskSet().tests[pos]) return getMaskSet().tests[pos];
            if (void 0 === ndxIntlzr) {
                for (var test, previousPos = pos - 1; void 0 === (test = getMaskSet().validPositions[previousPos]) && previousPos > -1 && (!getMaskSet().tests[previousPos] || void 0 === (test = getMaskSet().tests[previousPos][0])) ;) previousPos--;
                void 0 !== test && previousPos > -1 && (testPos = previousPos, ndxInitializer = test.locator.slice());
            }
            for (var mtndx = ndxInitializer.shift() ; mtndx < maskTokens.length; mtndx++) {
                var match = resolveTestFromToken(maskTokens[mtndx], ndxInitializer, [mtndx]);
                if (match && testPos === pos || testPos > pos) break;
            }
            return (0 === matches.length || insertStop) && matches.push({
                match: {
                    fn: null,
                    cardinality: 0,
                    optionality: !0,
                    casing: null,
                    def: ""
                },
                locator: []
            }), getMaskSet().tests[pos] = $.extend(!0, [], matches), getMaskSet().tests[pos];
        }
        function getBufferTemplate() {
            return void 0 === getMaskSet()._buffer && (getMaskSet()._buffer = getMaskTemplate(!1, 1)),
            getMaskSet()._buffer;
        }
        function getBuffer() {
            return void 0 === getMaskSet().buffer && (getMaskSet().buffer = getMaskTemplate(!0, getLastValidPosition(), !0)),
            getMaskSet().buffer;
        }
        function refreshFromBuffer(start, end, buffer) {
            var i;
            if (buffer = buffer || getBuffer().slice(), start === !0) resetMaskSet(), start = 0,
            end = buffer.length; else for (i = start; end > i; i++) delete getMaskSet().validPositions[i],
            delete getMaskSet().tests[i];
            for (i = start; end > i; i++) resetMaskSet(!0), buffer[i] !== opts.skipOptionalPartCharacter && isValid(i, buffer[i], !0, !0);
        }
        function casing(elem, test) {
            switch (test.casing) {
                case "upper":
                    elem = elem.toUpperCase();
                    break;

                case "lower":
                    elem = elem.toLowerCase();
            }
            return elem;
        }
        function checkAlternationMatch(altArr1, altArr2) {
            for (var altArrC = opts.greedy ? altArr2 : altArr2.slice(0, 1), isMatch = !1, alndx = 0; alndx < altArr1.length; alndx++) if (-1 !== $.inArray(altArr1[alndx], altArrC)) {
                isMatch = !0;
                break;
            }
            return isMatch;
        }
        function isValid(pos, c, strict, fromSetValid) {
            function _isValid(position, c, strict, fromSetValid) {
                var rslt = !1;
                return $.each(getTests(position), function (ndx, tst) {
                    for (var test = tst.match, loopend = c ? 1 : 0, chrs = "", i = test.cardinality; i > loopend; i--) chrs += getBufferElement(position - (i - 1));
                    if (c && (chrs += c), rslt = null != test.fn ? test.fn.test(chrs, getMaskSet(), position, strict, opts) : c !== test.def && c !== opts.skipOptionalPartCharacter || "" === test.def ? !1 : {
                        c: test.def,
                        pos: position
                    }, rslt !== !1) {
                        var elem = void 0 !== rslt.c ? rslt.c : c;
                        elem = elem === opts.skipOptionalPartCharacter && null === test.fn ? test.def : elem;
                        var validatedPos = position, possibleModifiedBuffer = getBuffer();
                        if (void 0 !== rslt.remove && ($.isArray(rslt.remove) || (rslt.remove = [rslt.remove]),
                        $.each(rslt.remove.sort(function (a, b) {
                            return b - a;
                        }), function (ndx, lmnt) {
                            stripValidPositions(lmnt, lmnt + 1, !0);
                        })), void 0 !== rslt.insert && ($.isArray(rslt.insert) || (rslt.insert = [rslt.insert]),
                        $.each(rslt.insert.sort(function (a, b) {
                            return a - b;
                        }), function (ndx, lmnt) {
                            isValid(lmnt.pos, lmnt.c, !0);
                        })), rslt.refreshFromBuffer) {
                            var refresh = rslt.refreshFromBuffer;
                            if (strict = !0, refreshFromBuffer(refresh === !0 ? refresh : refresh.start, refresh.end, possibleModifiedBuffer),
                            void 0 === rslt.pos && void 0 === rslt.c) return rslt.pos = getLastValidPosition(),
                            !1;
                            if (validatedPos = void 0 !== rslt.pos ? rslt.pos : position, validatedPos !== position) return rslt = $.extend(rslt, isValid(validatedPos, elem, !0)),
                            !1;
                        } else if (rslt !== !0 && void 0 !== rslt.pos && rslt.pos !== position && (validatedPos = rslt.pos,
                        refreshFromBuffer(position, validatedPos), validatedPos !== position)) return rslt = $.extend(rslt, isValid(validatedPos, elem, !0)),
                        !1;
                        return rslt !== !0 && void 0 === rslt.pos && void 0 === rslt.c ? !1 : (ndx > 0 && resetMaskSet(!0),
                        setValidPosition(validatedPos, $.extend({}, tst, {
                            input: casing(elem, test)
                        }), fromSetValid) || (rslt = !1), !1);
                    }
                }), rslt;
            }
            function alternate(pos, c, strict, fromSetValid) {
                for (var lastAlt, alternation, isValidRslt, altPos, i, validPos, validPsClone = $.extend(!0, {}, getMaskSet().validPositions), lAlt = getLastValidPosition() ; lAlt >= 0 && (altPos = getMaskSet().validPositions[lAlt],
                !altPos || void 0 === altPos.alternation || (lastAlt = lAlt, alternation = getMaskSet().validPositions[lastAlt].alternation,
                getTestTemplate(lastAlt).locator[altPos.alternation] === altPos.locator[altPos.alternation])) ; lAlt--);
                if (void 0 !== alternation) {
                    lastAlt = parseInt(lastAlt);
                    for (var decisionPos in getMaskSet().validPositions) if (decisionPos = parseInt(decisionPos),
                    altPos = getMaskSet().validPositions[decisionPos], decisionPos >= lastAlt && void 0 !== altPos.alternation) {
                        var altNdxs = getMaskSet().validPositions[lastAlt].locator[alternation].toString().split(","), decisionTaker = altPos.locator[alternation] || altNdxs[0];
                        decisionTaker.length > 0 && (decisionTaker = decisionTaker.split(",")[0]);
                        for (var mndx = 0; mndx < altNdxs.length; mndx++) if (decisionTaker < altNdxs[mndx]) {
                            for (var possibilityPos, possibilities, dp = decisionPos; dp >= 0; dp--) if (possibilityPos = getMaskSet().validPositions[dp],
                            void 0 !== possibilityPos) {
                                possibilities = possibilityPos.locator[alternation], possibilityPos.locator[alternation] = parseInt(altNdxs[mndx]);
                                break;
                            }
                            if (decisionTaker !== possibilityPos.locator[alternation]) {
                                var validInputs = [], staticInputsBeforePos = 0;
                                for (i = decisionPos + 1; i < getLastValidPosition() + 1; i++) validPos = getMaskSet().validPositions[i],
                                validPos && (null != validPos.match.fn ? validInputs.push(validPos.input) : pos > i && staticInputsBeforePos++),
                                delete getMaskSet().validPositions[i], delete getMaskSet().tests[i];
                                for (resetMaskSet(!0), opts.keepStatic = !opts.keepStatic, isValidRslt = !0; validInputs.length > 0;) {
                                    var input = validInputs.shift();
                                    if (input !== opts.skipOptionalPartCharacter && !(isValidRslt = isValid(getLastValidPosition() + 1, input, !1, !0))) break;
                                }
                                if (possibilityPos.alternation = alternation, possibilityPos.locator[alternation] = possibilities,
                                isValidRslt) {
                                    var targetLvp = getLastValidPosition(pos) + 1, staticInputsBeforePosAlternate = 0;
                                    for (i = decisionPos + 1; i < getLastValidPosition() + 1; i++) validPos = getMaskSet().validPositions[i],
                                    validPos && null == validPos.match.fn && pos > i && staticInputsBeforePosAlternate++;
                                    pos += staticInputsBeforePosAlternate - staticInputsBeforePos, isValidRslt = isValid(pos > targetLvp ? targetLvp : pos, c, strict, fromSetValid);
                                }
                                if (opts.keepStatic = !opts.keepStatic, isValidRslt) return isValidRslt;
                                resetMaskSet(), getMaskSet().validPositions = $.extend(!0, {}, validPsClone);
                            }
                        }
                        break;
                    }
                }
                return !1;
            }
            function trackbackAlternations(originalPos, newPos) {
                for (var vp = getMaskSet().validPositions[newPos], targetLocator = vp.locator, tll = targetLocator.length, ps = originalPos; newPos > ps; ps++) if (!isMask(ps)) {
                    var tests = getTests(ps), bestMatch = tests[0], equality = -1;
                    $.each(tests, function (ndx, tst) {
                        for (var i = 0; tll > i; i++) tst.locator[i] && checkAlternationMatch(tst.locator[i].toString().split(","), targetLocator[i].toString().split(",")) && i > equality && (equality = i,
                        bestMatch = tst);
                    }), setValidPosition(ps, $.extend({}, bestMatch, {
                        input: bestMatch.match.def
                    }), !0);
                }
            }
            strict = strict === !0;
            for (var buffer = getBuffer(), pndx = pos - 1; pndx > -1 && !getMaskSet().validPositions[pndx]; pndx--);
            for (pndx++; pos > pndx; pndx++) void 0 === getMaskSet().validPositions[pndx] && ((!isMask(pndx) || buffer[pndx] !== getPlaceholder(pndx)) && getTests(pndx).length > 1 || buffer[pndx] === opts.radixPoint || "0" === buffer[pndx] && $.inArray(opts.radixPoint, buffer) < pndx) && _isValid(pndx, buffer[pndx], !0);
            var maskPos = pos, result = !1, positionsClone = $.extend(!0, {}, getMaskSet().validPositions);
            if (maskPos < getMaskLength() && (getBuffer(), result = _isValid(maskPos, c, strict, fromSetValid),
            (!strict || fromSetValid) && result === !1)) {
                var currentPosValid = getMaskSet().validPositions[maskPos];
                if (!currentPosValid || null !== currentPosValid.match.fn || currentPosValid.match.def !== c && c !== opts.skipOptionalPartCharacter) {
                    if ((opts.insertMode || void 0 === getMaskSet().validPositions[seekNext(maskPos)]) && !isMask(maskPos)) for (var nPos = maskPos + 1, snPos = seekNext(maskPos) ; snPos >= nPos; nPos++) if (result = _isValid(nPos, c, strict, fromSetValid),
                    result !== !1) {
                        trackbackAlternations(maskPos, nPos), maskPos = nPos;
                        break;
                    }
                } else result = {
                    caret: seekNext(maskPos)
                };
            }
            if (result === !1 && opts.keepStatic && isComplete(buffer) && (result = alternate(pos, c, strict, fromSetValid)),
            result === !0 && (result = {
                pos: maskPos
            }), $.isFunction(opts.postValidation) && result !== !1 && !strict) {
                resetMaskSet(!0);
                var postValidResult = opts.postValidation(getBuffer(), opts);
                if (postValidResult) {
                    if (postValidResult.refreshFromBuffer) {
                        var refresh = postValidResult.refreshFromBuffer;
                        refreshFromBuffer(refresh === !0 ? refresh : refresh.start, refresh.end, postValidResult.buffer),
                        resetMaskSet(!0), result = postValidResult;
                    }
                } else resetMaskSet(!0), getMaskSet().validPositions = $.extend(!0, {}, positionsClone),
                result = !1;
            }
            return result;
        }
        function isMask(pos) {
            var test = getTest(pos);
            if (null != test.fn) return test.fn;
            if (!opts.keepStatic && void 0 === getMaskSet().validPositions[pos]) {
                for (var tests = getTests(pos), staticAlternations = !0, i = 0; i < tests.length; i++) if ("" !== tests[i].match.def && (void 0 === tests[i].alternation || tests[i].locator[tests[i].alternation].length > 1)) {
                    staticAlternations = !1;
                    break;
                }
                return staticAlternations;
            }
            return !1;
        }
        function getMaskLength() {
            var maskLength;
            maxLength = void 0 !== el ? el.maxLength : void 0, -1 === maxLength && (maxLength = void 0);
            var pos, lvp = getLastValidPosition(), testPos = getMaskSet().validPositions[lvp], ndxIntlzr = void 0 !== testPos ? testPos.locator.slice() : void 0;
            for (pos = lvp + 1; void 0 === testPos || null !== testPos.match.fn || null === testPos.match.fn && "" !== testPos.match.def; pos++) testPos = getTestTemplate(pos, ndxIntlzr, pos - 1),
            ndxIntlzr = testPos.locator.slice();
            var lastTest = getTest(pos - 1);
            return maskLength = "" !== lastTest.def ? pos : pos - 1, void 0 === maxLength || maxLength > maskLength ? maskLength : maxLength;
        }
        function seekNext(pos, newBlock) {
            var maskL = getMaskLength();
            if (pos >= maskL) return maskL;
            for (var position = pos; ++position < maskL && (newBlock === !0 && (getTest(position).newBlockMarker !== !0 || !isMask(position)) || newBlock !== !0 && !isMask(position) && (opts.nojumps !== !0 || opts.nojumpsThreshold > position)) ;);
            return position;
        }
        function seekPrevious(pos, newBlock) {
            var position = pos;
            if (0 >= position) return 0;
            for (; --position > 0 && (newBlock === !0 && getTest(position).newBlockMarker !== !0 || newBlock !== !0 && !isMask(position)) ;);
            return position;
        }
        function getBufferElement(position) {
            return void 0 === getMaskSet().validPositions[position] ? getPlaceholder(position) : getMaskSet().validPositions[position].input;
        }
        function writeBuffer(input, buffer, caretPos, event, triggerInputEvent) {
            if (event && $.isFunction(opts.onBeforeWrite)) {
                var result = opts.onBeforeWrite.call(input, event, buffer, caretPos, opts);
                if (result) {
                    if (result.refreshFromBuffer) {
                        var refresh = result.refreshFromBuffer;
                        refreshFromBuffer(refresh === !0 ? refresh : refresh.start, refresh.end, result.buffer || buffer),
                        resetMaskSet(!0), buffer = getBuffer();
                    }
                    caretPos = void 0 !== result.caret ? result.caret : caretPos;
                }
            }
            input.inputmask._valueSet(buffer.join("")), void 0 === caretPos || void 0 !== event && "blur" === event.type || caret(input, caretPos),
            triggerInputEvent === !0 && (skipInputEvent = !0, $(input).trigger("input"));
        }
        function getPlaceholder(pos, test) {
            if (test = test || getTest(pos), void 0 !== test.placeholder) return test.placeholder;
            if (null === test.fn) {
                if (!opts.keepStatic && void 0 === getMaskSet().validPositions[pos]) {
                    for (var prevTest, tests = getTests(pos), hasAlternations = !1, i = 0; i < tests.length; i++) {
                        if (prevTest && "" !== tests[i].match.def && tests[i].match.def !== prevTest.match.def && (void 0 === tests[i].alternation || tests[i].alternation === prevTest.alternation)) {
                            hasAlternations = !0;
                            break;
                        }
                        tests[i].match.optionality !== !0 && tests[i].match.optionalQuantifier !== !0 && (prevTest = tests[i]);
                    }
                    if (hasAlternations) return opts.placeholder.charAt(pos % opts.placeholder.length);
                }
                return test.def;
            }
            return opts.placeholder.charAt(pos % opts.placeholder.length);
        }
        function checkVal(input, writeOut, strict, nptvl) {
            function isTemplateMatch() {
                var isMatch = !1, charCodeNdx = getBufferTemplate().slice(initialNdx, seekNext(initialNdx)).join("").indexOf(charCodes);
                if (-1 !== charCodeNdx && !isMask(initialNdx)) {
                    isMatch = !0;
                    for (var bufferTemplateArr = getBufferTemplate().slice(initialNdx, initialNdx + charCodeNdx), i = 0; i < bufferTemplateArr.length; i++) if (" " !== bufferTemplateArr[i]) {
                        isMatch = !1;
                        break;
                    }
                }
                return isMatch;
            }
            var inputValue = void 0 !== nptvl ? nptvl.slice() : input.inputmask._valueGet().split(""), charCodes = "", initialNdx = 0;
            if (resetMaskSet(), getMaskSet().p = seekNext(-1), writeOut && input.inputmask._valueSet(""),
            !strict) if (opts.autoUnmask !== !0) {
                var staticInput = getBufferTemplate().slice(0, seekNext(-1)).join(""), matches = inputValue.join("").match(new RegExp("^" + Inputmask.escapeRegex(staticInput), "g"));
                matches && matches.length > 0 && (inputValue.splice(0, matches.length * staticInput.length),
                initialNdx = seekNext(initialNdx));
            } else initialNdx = seekNext(initialNdx);
            $.each(inputValue, function (ndx, charCode) {
                var keypress = $.Event("keypress");
                keypress.which = charCode.charCodeAt(0), charCodes += charCode;
                var lvp = getLastValidPosition(void 0, !0), lvTest = getMaskSet().validPositions[lvp], nextTest = getTestTemplate(lvp + 1, lvTest ? lvTest.locator.slice() : void 0, lvp);
                if (!isTemplateMatch() || strict || opts.autoUnmask) {
                    var pos = strict ? ndx : null == nextTest.match.fn && nextTest.match.optionality && lvp + 1 < getMaskSet().p ? lvp + 1 : getMaskSet().p;
                    keypressEvent.call(input, keypress, !0, !1, strict, pos), initialNdx = pos + 1,
                    charCodes = "";
                } else keypressEvent.call(input, keypress, !0, !1, !0, lvp + 1);
            }), writeOut && writeBuffer(input, getBuffer(), document.activeElement === input ? seekNext(getLastValidPosition(0)) : void 0, $.Event("checkval"));
        }
        function unmaskedvalue(input) {
            if (input.inputmask) {
                if (void 0 === input.className || -1 === input.className.indexOf("hasDatepicker")) {
                    var umValue = [], vps = getMaskSet().validPositions;
                    for (var pndx in vps) vps[pndx].match && null != vps[pndx].match.fn && umValue.push(vps[pndx].input);
                    var unmaskedValue = 0 === umValue.length ? null : (isRTL ? umValue.reverse() : umValue).join("");
                    if (null !== unmaskedValue) {
                        var bufferValue = (isRTL ? getBuffer().slice().reverse() : getBuffer()).join("");
                        $.isFunction(opts.onUnMask) && (unmaskedValue = opts.onUnMask.call(input, bufferValue, unmaskedValue, opts) || unmaskedValue);
                    }
                    return unmaskedValue;
                }
                return input.inputmask._valueGet();
            }
            return input.value;
        }
        function caret(input, begin, end) {
            function translatePosition(pos) {
                if (isRTL && "number" == typeof pos && (!opts.greedy || "" !== opts.placeholder)) {
                    var bffrLght = getBuffer().join("").length;
                    pos = bffrLght - pos;
                }
                return pos;
            }
            var range;
            if ("number" != typeof begin) return input.setSelectionRange ? (begin = input.selectionStart,
            end = input.selectionEnd) : window.getSelection ? (range = window.getSelection().getRangeAt(0),
            (range.commonAncestorContainer.parentNode === input || range.commonAncestorContainer === input) && (begin = range.startOffset,
            end = range.endOffset)) : document.selection && document.selection.createRange && (range = document.selection.createRange(),
            begin = 0 - range.duplicate().moveStart("character", -1e5), end = begin + range.text.length),
            {
                begin: translatePosition(begin),
                end: translatePosition(end)
            };
            begin = translatePosition(begin), end = translatePosition(end), end = "number" == typeof end ? end : begin;
            var scrollCalc = input.style.fontSize.replace("px", "") * end;
            if (input.scrollLeft = scrollCalc > input.scrollWidth ? scrollCalc : 0, androidchrome || opts.insertMode !== !1 || begin !== end || end++,
            input.setSelectionRange) input.selectionStart = begin, input.selectionEnd = end; else if (window.getSelection) {
                if (range = document.createRange(), void 0 === input.firstChild) {
                    var textNode = document.createTextNode("");
                    input.appendChild(textNode);
                }
                range.setStart(input.firstChild, begin < input.inputmask._valueGet().length ? begin : input.inputmask._valueGet().length),
                range.setEnd(input.firstChild, end < input.inputmask._valueGet().length ? end : input.inputmask._valueGet().length),
                range.collapse(!0);
                var sel = window.getSelection();
                sel.removeAllRanges(), sel.addRange(range);
            } else input.createTextRange && (range = input.createTextRange(), range.collapse(!0),
            range.moveEnd("character", end), range.moveStart("character", begin), range.select());
        }
        function determineLastRequiredPosition(returnDefinition) {
            var pos, testPos, buffer = getBuffer(), bl = buffer.length, lvp = getLastValidPosition(), positions = {}, lvTest = getMaskSet().validPositions[lvp], ndxIntlzr = void 0 !== lvTest ? lvTest.locator.slice() : void 0;
            for (pos = lvp + 1; pos < buffer.length; pos++) testPos = getTestTemplate(pos, ndxIntlzr, pos - 1),
            ndxIntlzr = testPos.locator.slice(), positions[pos] = $.extend(!0, {}, testPos);
            var lvTestAlt = lvTest && void 0 !== lvTest.alternation ? lvTest.locator[lvTest.alternation] : void 0;
            for (pos = bl - 1; pos > lvp && (testPos = positions[pos], (testPos.match.optionality || testPos.match.optionalQuantifier || lvTestAlt && (lvTestAlt !== positions[pos].locator[lvTest.alternation] && null != testPos.match.fn || null === testPos.match.fn && testPos.locator[lvTest.alternation] && checkAlternationMatch(testPos.locator[lvTest.alternation].toString().split(","), lvTestAlt.toString().split(",")) && "" !== getTests(pos)[0].def)) && buffer[pos] === getPlaceholder(pos, testPos.match)) ; pos--) bl--;
            return returnDefinition ? {
                l: bl,
                def: positions[bl] ? positions[bl].match : void 0
            } : bl;
        }
        function clearOptionalTail(buffer) {
            for (var rl = determineLastRequiredPosition(), lmib = buffer.length - 1; lmib > rl && !isMask(lmib) ; lmib--);
            return buffer.splice(rl, lmib + 1 - rl), buffer;
        }
        function isComplete(buffer) {
            if ($.isFunction(opts.isComplete)) return opts.isComplete.call(el, buffer, opts);
            if ("*" === opts.repeat) return void 0;
            var complete = !1, lrp = determineLastRequiredPosition(!0), aml = seekPrevious(lrp.l);
            if (void 0 === lrp.def || lrp.def.newBlockMarker || lrp.def.optionality || lrp.def.optionalQuantifier) {
                complete = !0;
                for (var i = 0; aml >= i; i++) {
                    var test = getTestTemplate(i).match;
                    if (null !== test.fn && void 0 === getMaskSet().validPositions[i] && test.optionality !== !0 && test.optionalQuantifier !== !0 || null === test.fn && buffer[i] !== getPlaceholder(i, test)) {
                        complete = !1;
                        break;
                    }
                }
            }
            return complete;
        }
        function isSelection(begin, end) {
            return isRTL ? begin - end > 1 || begin - end === 1 && opts.insertMode : end - begin > 1 || end - begin === 1 && opts.insertMode;
        }
        function installEventRuler(npt) {
            var events = $._data(npt).events, inComposition = !1;
            $.each(events, function (eventType, eventHandlers) {
                $.each(eventHandlers, function (ndx, eventHandler) {
                    if ("inputmask" === eventHandler.namespace) {
                        var handler = eventHandler.handler;
                        eventHandler.handler = function (e) {
                            if (void 0 === this.inputmask) {
                                var imOpts = $.data(this, "_inputmask_opts");
                                imOpts ? new Inputmask(imOpts).mask(this) : $(this).off(".inputmask");
                            } else {
                                if ("setvalue" === e.type || !(this.disabled || this.readOnly && !("keydown" === e.type && e.ctrlKey && 67 === e.keyCode || opts.tabThrough === !1 && e.keyCode === Inputmask.keyCode.TAB))) {
                                    switch (e.type) {
                                        case "input":
                                            if (skipInputEvent === !0 || inComposition === !0) return skipInputEvent = !1, e.preventDefault();
                                            break;

                                        case "keydown":
                                            skipKeyPressEvent = !1, inComposition = !1;
                                            break;

                                        case "keypress":
                                            if (skipKeyPressEvent === !0) return e.preventDefault();
                                            skipKeyPressEvent = !0;
                                            break;

                                        case "compositionstart":
                                            inComposition = !0;
                                            break;

                                        case "compositionupdate":
                                            skipInputEvent = !0;
                                            break;

                                        case "compositionend":
                                            inComposition = !1;
                                    }
                                    return handler.apply(this, arguments);
                                }
                                e.preventDefault();
                            }
                        };
                    }
                });
            });
        }
        function patchValueProperty(npt) {
            function patchValhook(type) {
                if ($.valHooks && void 0 === $.valHooks[type] || $.valHooks[type].inputmaskpatch !== !0) {
                    var valhookGet = $.valHooks[type] && $.valHooks[type].get ? $.valHooks[type].get : function (elem) {
                        return elem.value;
                    }, valhookSet = $.valHooks[type] && $.valHooks[type].set ? $.valHooks[type].set : function (elem, value) {
                        return elem.value = value, elem;
                    };
                    $.valHooks[type] = {
                        get: function (elem) {
                            if (elem.inputmask) {
                                if (elem.inputmask.opts.autoUnmask) return elem.inputmask.unmaskedvalue();
                                var result = valhookGet(elem), maskset = elem.inputmask.maskset, bufferTemplate = maskset._buffer;
                                return bufferTemplate = bufferTemplate ? bufferTemplate.join("") : "", result !== bufferTemplate ? result : "";
                            }
                            return valhookGet(elem);
                        },
                        set: function (elem, value) {
                            var result, $elem = $(elem);
                            return result = valhookSet(elem, value), elem.inputmask && $elem.triggerHandler("setvalue.inputmask"),
                            result;
                        },
                        inputmaskpatch: !0
                    };
                }
            }
            function getter() {
                return this.inputmask ? this.inputmask.opts.autoUnmask ? this.inputmask.unmaskedvalue() : valueGet.call(this) !== getBufferTemplate().join("") ? valueGet.call(this) : "" : valueGet.call(this);
            }
            function setter(value) {
                valueSet.call(this, value), this.inputmask && $(this).triggerHandler("setvalue.inputmask");
            }
            function installNativeValueSetFallback(npt) {
                $(npt).on("mouseenter.inputmask", function (event) {
                    var $input = $(this), input = this, value = input.inputmask._valueGet();
                    "" !== value && value !== getBuffer().join("") && $input.triggerHandler("setvalue.inputmask");
                });
                //!! the bound handlers are executed in the order they where bound
                var events = $._data(npt).events, handlers = events.mouseover;
                if (handlers) {
                    for (var ourHandler = handlers[handlers.length - 1], i = handlers.length - 1; i > 0; i--) handlers[i] = handlers[i - 1];
                    handlers[0] = ourHandler;
                }
            }
            var valueGet, valueSet;
            npt.inputmask.__valueGet || (Object.getOwnPropertyDescriptor && void 0 === npt.value ? (valueGet = function () {
                return this.textContent;
            }, valueSet = function (value) {
                this.textContent = value;
            }, Object.defineProperty(npt, "value", {
                get: getter,
                set: setter
            })) : document.__lookupGetter__ && npt.__lookupGetter__("value") ? (valueGet = npt.__lookupGetter__("value"),
            valueSet = npt.__lookupSetter__("value"), npt.__defineGetter__("value", getter),
            npt.__defineSetter__("value", setter)) : (valueGet = function () {
                return npt.value;
            }, valueSet = function (value) {
                npt.value = value;
            }, patchValhook(npt.type), installNativeValueSetFallback(npt)), npt.inputmask.__valueGet = valueGet,
            npt.inputmask._valueGet = function (overruleRTL) {
                return isRTL && overruleRTL !== !0 ? valueGet.call(this.el).split("").reverse().join("") : valueGet.call(this.el);
            }, npt.inputmask.__valueSet = valueSet, npt.inputmask._valueSet = function (value, overruleRTL) {
                valueSet.call(this.el, overruleRTL !== !0 && isRTL ? value.split("").reverse().join("") : value);
            });
        }
        function handleRemove(input, k, pos, strict) {
            function generalize() {
                if (opts.keepStatic) {
                    resetMaskSet(!0);
                    var lastAlt, validInputs = [], positionsClone = $.extend(!0, {}, getMaskSet().validPositions);
                    for (lastAlt = getLastValidPosition() ; lastAlt >= 0; lastAlt--) {
                        var validPos = getMaskSet().validPositions[lastAlt];
                        if (validPos && (null != validPos.match.fn && validInputs.push(validPos.input),
                        delete getMaskSet().validPositions[lastAlt], void 0 !== validPos.alternation && validPos.locator[validPos.alternation] === getTestTemplate(lastAlt).locator[validPos.alternation])) break;
                    }
                    if (lastAlt > -1) for (; validInputs.length > 0;) {
                        getMaskSet().p = seekNext(getLastValidPosition());
                        var keypress = $.Event("keypress");
                        keypress.which = validInputs.pop().charCodeAt(0), keypressEvent.call(input, keypress, !0, !1, !1, getMaskSet().p);
                    } else getMaskSet().validPositions = $.extend(!0, {}, positionsClone);
                }
            }
            if ((opts.numericInput || isRTL) && (k === Inputmask.keyCode.BACKSPACE ? k = Inputmask.keyCode.DELETE : k === Inputmask.keyCode.DELETE && (k = Inputmask.keyCode.BACKSPACE),
            isRTL)) {
                var pend = pos.end;
                pos.end = pos.begin, pos.begin = pend;
            }
            k === Inputmask.keyCode.BACKSPACE && (pos.end - pos.begin < 1 || opts.insertMode === !1) ? (pos.begin = seekPrevious(pos.begin),
            void 0 === getMaskSet().validPositions[pos.begin] || getMaskSet().validPositions[pos.begin].input !== opts.groupSeparator && getMaskSet().validPositions[pos.begin].input !== opts.radixPoint || pos.begin--) : k === Inputmask.keyCode.DELETE && pos.begin === pos.end && (pos.end = isMask(pos.end) ? pos.end + 1 : seekNext(pos.end) + 1,
            void 0 === getMaskSet().validPositions[pos.begin] || getMaskSet().validPositions[pos.begin].input !== opts.groupSeparator && getMaskSet().validPositions[pos.begin].input !== opts.radixPoint || pos.end++),
            stripValidPositions(pos.begin, pos.end, !1, strict), strict !== !0 && generalize();
            var lvp = getLastValidPosition(pos.begin);
            lvp < pos.begin ? (-1 === lvp && resetMaskSet(), getMaskSet().p = seekNext(lvp)) : strict !== !0 && (getMaskSet().p = pos.begin);
        }
        function keydownEvent(e) {
            var input = this, $input = $(input), k = e.keyCode, pos = caret(input);
            k === Inputmask.keyCode.BACKSPACE || k === Inputmask.keyCode.DELETE || iphone && 127 === k || e.ctrlKey && 88 === k && !isInputEventSupported("cut") ? (e.preventDefault(),
            88 === k && (undoValue = getBuffer().join("")), handleRemove(input, k, pos), writeBuffer(input, getBuffer(), getMaskSet().p, e, undoValue !== getBuffer().join("")),
            input.inputmask._valueGet() === getBufferTemplate().join("") ? $input.trigger("cleared") : isComplete(getBuffer()) === !0 && $input.trigger("complete"),
            opts.showTooltip && $input.prop("title", getMaskSet().mask)) : k === Inputmask.keyCode.END || k === Inputmask.keyCode.PAGE_DOWN ? setTimeout(function () {
                var caretPos = seekNext(getLastValidPosition());
                opts.insertMode || caretPos !== getMaskLength() || e.shiftKey || caretPos--, caret(input, e.shiftKey ? pos.begin : caretPos, caretPos);
            }, 0) : k === Inputmask.keyCode.HOME && !e.shiftKey || k === Inputmask.keyCode.PAGE_UP ? caret(input, 0, e.shiftKey ? pos.begin : 0) : (opts.undoOnEscape && k === Inputmask.keyCode.ESCAPE || 90 === k && e.ctrlKey) && e.altKey !== !0 ? (checkVal(input, !0, !1, undoValue.split("")),
            $input.trigger("click")) : k !== Inputmask.keyCode.INSERT || e.shiftKey || e.ctrlKey ? opts.tabThrough === !0 && k === Inputmask.keyCode.TAB ? (e.shiftKey === !0 ? (null === getTest(pos.begin).fn && (pos.begin = seekNext(pos.begin)),
            pos.end = seekPrevious(pos.begin, !0), pos.begin = seekPrevious(pos.end, !0)) : (pos.begin = seekNext(pos.begin, !0),
            pos.end = seekNext(pos.begin, !0), pos.end < getMaskLength() && pos.end--), pos.begin < getMaskLength() && (e.preventDefault(),
            caret(input, pos.begin, pos.end))) : opts.insertMode !== !1 || e.shiftKey || (k === Inputmask.keyCode.RIGHT ? setTimeout(function () {
                var caretPos = caret(input);
                caret(input, caretPos.begin);
            }, 0) : k === Inputmask.keyCode.LEFT && setTimeout(function () {
                var caretPos = caret(input);
                caret(input, isRTL ? caretPos.begin + 1 : caretPos.begin - 1);
            }, 0)) : (opts.insertMode = !opts.insertMode, caret(input, opts.insertMode || pos.begin !== getMaskLength() ? pos.begin : pos.begin - 1)),
            opts.onKeyDown.call(this, e, getBuffer(), caret(input).begin, opts), ignorable = -1 !== $.inArray(k, opts.ignorables);
        }
        function keypressEvent(e, checkval, writeOut, strict, ndx) {
            var input = this, $input = $(input), k = e.which || e.charCode || e.keyCode;
            if (!(checkval === !0 || e.ctrlKey && e.altKey) && (e.ctrlKey || e.metaKey || ignorable)) return k === Inputmask.keyCode.ENTER && undoValue !== getBuffer().join("") && setTimeout(function () {
                $input.trigger("change"), undoValue = getBuffer().join("");
            }, 0), !0;
            if (k) {
                46 === k && e.shiftKey === !1 && "," === opts.radixPoint && (k = 44);
                var forwardPosition, pos = checkval ? {
                    begin: ndx,
                    end: ndx
                } : caret(input), c = String.fromCharCode(k), isSlctn = isSelection(pos.begin, pos.end);
                isSlctn && (getMaskSet().undoPositions = $.extend(!0, {}, getMaskSet().validPositions),
                handleRemove(input, Inputmask.keyCode.DELETE, pos, !0), pos.begin = getMaskSet().p,
                opts.insertMode || (opts.insertMode = !opts.insertMode, setValidPosition(pos.begin, strict),
                opts.insertMode = !opts.insertMode), isSlctn = !opts.multi), getMaskSet().writeOutBuffer = !0;
                var p = isRTL && !isSlctn ? pos.end : pos.begin, valResult = isValid(p, c, strict);
                if (valResult !== !1) {
                    if (valResult !== !0 && (p = void 0 !== valResult.pos ? valResult.pos : p, c = void 0 !== valResult.c ? valResult.c : c),
                    resetMaskSet(!0), void 0 !== valResult.caret) forwardPosition = valResult.caret; else {
                        var vps = getMaskSet().validPositions;
                        forwardPosition = !opts.keepStatic && (void 0 !== vps[p + 1] && getTests(p + 1, vps[p].locator.slice(), p).length > 1 || void 0 !== vps[p].alternation) ? p + 1 : seekNext(p);
                    }
                    getMaskSet().p = forwardPosition;
                }
                if (writeOut !== !1) {
                    var self = this;
                    if (setTimeout(function () {
                        opts.onKeyValidation.call(self, valResult, opts);
                    }, 0), getMaskSet().writeOutBuffer && valResult !== !1) {
                        var buffer = getBuffer();
                        writeBuffer(input, buffer, checkval ? void 0 : opts.numericInput ? seekPrevious(forwardPosition) : forwardPosition, e, checkval !== !0),
                        checkval !== !0 && setTimeout(function () {
                            isComplete(buffer) === !0 && $input.trigger("complete");
                        }, 0);
                    } else isSlctn && (getMaskSet().buffer = void 0, getMaskSet().validPositions = getMaskSet().undoPositions);
                } else isSlctn && (getMaskSet().buffer = void 0, getMaskSet().validPositions = getMaskSet().undoPositions);
                if (opts.showTooltip && $input.prop("title", getMaskSet().mask), checkval && $.isFunction(opts.onBeforeWrite)) {
                    var result = opts.onBeforeWrite.call(this, e, getBuffer(), forwardPosition, opts);
                    if (result && result.refreshFromBuffer) {
                        var refresh = result.refreshFromBuffer;
                        refreshFromBuffer(refresh === !0 ? refresh : refresh.start, refresh.end, result.buffer),
                        resetMaskSet(!0), result.caret && (getMaskSet().p = result.caret);
                    }
                }
                if (e.preventDefault(), checkval) return valResult;
            }
        }
        function pasteEvent(e) {
            var input = this, $input = $(input), inputValue = input.inputmask._valueGet(!0), caretPos = caret(input);
            if ("propertychange" === e.type && input.inputmask._valueGet().length <= getMaskLength()) return !0;
            if ("paste" === e.type) {
                var valueBeforeCaret = inputValue.substr(0, caretPos.begin), valueAfterCaret = inputValue.substr(caretPos.end, inputValue.length);
                valueBeforeCaret === getBufferTemplate().slice(0, caretPos.begin).join("") && (valueBeforeCaret = ""),
                valueAfterCaret === getBufferTemplate().slice(caretPos.end).join("") && (valueAfterCaret = ""),
                window.clipboardData && window.clipboardData.getData ? inputValue = valueBeforeCaret + window.clipboardData.getData("Text") + valueAfterCaret : e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.getData && (inputValue = valueBeforeCaret + e.originalEvent.clipboardData.getData("text/plain") + valueAfterCaret);
            }
            var pasteValue = inputValue;
            if ($.isFunction(opts.onBeforePaste)) {
                if (pasteValue = opts.onBeforePaste.call(input, inputValue, opts), pasteValue === !1) return e.preventDefault(),
                !1;
                pasteValue || (pasteValue = inputValue);
            }
            return checkVal(input, !1, !1, isRTL ? pasteValue.split("").reverse() : pasteValue.toString().split("")),
            writeBuffer(input, getBuffer(), void 0, e, !0), $input.trigger("click"), isComplete(getBuffer()) === !0 && $input.trigger("complete"),
            !1;
        }
        function inputFallBackEvent(e) {
            var input = this;
            checkVal(input, !0, !1), isComplete(getBuffer()) === !0 && $(input).trigger("complete"),
            e.preventDefault();
        }
        function compositionStartEvent(e) {
            var input = this;
            undoValue = getBuffer().join(""), ("" === compositionData || 0 !== e.originalEvent.data.indexOf(compositionData)) && (compositionCaretPos = caret(input));
        }
        function compositionUpdateEvent(e) {
            var input = this, caretPos = caret(input);
            0 === e.originalEvent.data.indexOf(compositionData) && (resetMaskSet(), caretPos = compositionCaretPos);
            var newData = e.originalEvent.data;
            caret(input, caretPos.begin, caretPos.end);
            for (var i = 0; i < newData.length; i++) {
                var keypress = $.Event("keypress");
                keypress.which = newData.charCodeAt(i), skipKeyPressEvent = !1, ignorable = !1,
                keypressEvent.call(input, keypress);
            }
            setTimeout(function () {
                var forwardPosition = getMaskSet().p;
                writeBuffer(input, getBuffer(), opts.numericInput ? seekPrevious(forwardPosition) : forwardPosition);
            }, 0), compositionData = e.originalEvent.data;
        }
        function compositionEndEvent(e) { }
        function setValueEvent(e) {
            var input = this, value = input.inputmask._valueGet();
            input.inputmask._valueSet($.isFunction(opts.onBeforeMask) ? opts.onBeforeMask.call(input, value, opts) || value : value),
            checkVal(input, !0, !1), undoValue = getBuffer().join(""), (opts.clearMaskOnLostFocus || opts.clearIncomplete) && input.inputmask._valueGet() === getBufferTemplate().join("") && input.inputmask._valueSet("");
        }
        function focusEvent(e) {
            var input = this, nptValue = input.inputmask._valueGet();
            opts.showMaskOnFocus && (!opts.showMaskOnHover || opts.showMaskOnHover && "" === nptValue) ? input.inputmask._valueGet() !== getBuffer().join("") && writeBuffer(input, getBuffer(), seekNext(getLastValidPosition())) : mouseEnter === !1 && caret(input, seekNext(getLastValidPosition())),
            opts.positionCaretOnTab === !0 && setTimeout(function () {
                caret(input, seekNext(getLastValidPosition()));
            }, 0), undoValue = getBuffer().join("");
        }
        function mouseleaveEvent(e) {
            var input = this;
            if (mouseEnter = !1, opts.clearMaskOnLostFocus) {
                var buffer = getBuffer().slice(), nptValue = input.inputmask._valueGet();
                document.activeElement !== input && nptValue !== input.getAttribute("placeholder") && "" !== nptValue && (-1 === getLastValidPosition() && nptValue === getBufferTemplate().join("") ? buffer = [] : clearOptionalTail(buffer),
                writeBuffer(input, buffer));
            }
        }
        function clickEvent(e) {
            function doRadixFocus(clickPos) {
                if (opts.radixFocus && "" !== opts.radixPoint) {
                    var vps = getMaskSet().validPositions;
                    if (void 0 === vps[clickPos] || vps[clickPos].input === getPlaceholder(clickPos)) {
                        if (clickPos < seekNext(-1)) return !0;
                        var radixPos = $.inArray(opts.radixPoint, getBuffer());
                        if (-1 !== radixPos) {
                            for (var vp in vps) if (vp > radixPos && vps[vp].input !== getPlaceholder(vp)) return !1;
                            return !0;
                        }
                    }
                }
                return !1;
            }
            var input = this;
            if (document.activeElement === input) {
                var selectedCaret = caret(input);
                if (selectedCaret.begin === selectedCaret.end) if (doRadixFocus(selectedCaret.begin)) caret(input, $.inArray(opts.radixPoint, getBuffer())); else {
                    var clickPosition = selectedCaret.begin, lastPosition = seekNext(getLastValidPosition(clickPosition));
                    lastPosition > clickPosition ? caret(input, isMask(clickPosition) || isMask(clickPosition - 1) ? clickPosition : seekNext(clickPosition)) : caret(input, opts.numericInput ? 0 : lastPosition);
                }
            }
        }
        function dblclickEvent(e) {
            var input = this;
            setTimeout(function () {
                caret(input, 0, seekNext(getLastValidPosition()));
            }, 0);
        }
        function cutEvent(e) {
            skipInputEvent = !0;
            var input = this, $input = $(input), pos = caret(input);
            if (isRTL) {
                var clipboardData = window.clipboardData || e.originalEvent.clipboardData, clipData = clipboardData.getData("text").split("").reverse().join("");
                clipboardData.setData("text", clipData);
            }
            handleRemove(input, Inputmask.keyCode.DELETE, pos), writeBuffer(input, getBuffer(), getMaskSet().p, e, undoValue !== getBuffer().join("")),
            input.inputmask._valueGet() === getBufferTemplate().join("") && $input.trigger("cleared"),
            opts.showTooltip && (input.title = getMaskSet().mask);
        }
        function blurEvent(e) {
            var $input = $(this), input = this;
            if (input.inputmask) {
                var nptValue = input.inputmask._valueGet(), buffer = getBuffer().slice();
                undoValue !== buffer.join("") && setTimeout(function () {
                    $input.trigger("change"), undoValue = buffer.join("");
                }, 0), "" !== nptValue && (opts.clearMaskOnLostFocus && (-1 === getLastValidPosition() && nptValue === getBufferTemplate().join("") ? buffer = [] : clearOptionalTail(buffer)),
                isComplete(buffer) === !1 && (setTimeout(function () {
                    $input.trigger("incomplete");
                }, 0), opts.clearIncomplete && (resetMaskSet(), buffer = opts.clearMaskOnLostFocus ? [] : getBufferTemplate().slice())),
                writeBuffer(input, buffer, void 0, e));
            }
        }
        function mouseenterEvent(e) {
            var input = this;
            mouseEnter = !0, document.activeElement !== input && opts.showMaskOnHover && input.inputmask._valueGet() !== getBuffer().join("") && writeBuffer(input, getBuffer());
        }
        function mask(elem) {
            el = elem, $el = $(el), opts.showTooltip && (el.title = getMaskSet().mask), ("rtl" === el.dir || opts.rightAlign) && (el.style.textAlign = "right"),
            ("rtl" === el.dir || opts.numericInput) && (el.dir = "ltr", el.removeAttribute("dir"),
            el.inputmask.isRTL = !0, isRTL = !0), $el.off(".inputmask"), ("INPUT" === el.tagName && isInputTypeSupported(el.getAttribute("type")) || el.isContentEditable) && ($(el.form).on("submit", function () {
                undoValue !== getBuffer().join("") && $el.trigger("change"), opts.clearMaskOnLostFocus && -1 === getLastValidPosition() && el.inputmask._valueGet && el.inputmask._valueGet() === getBufferTemplate().join("") && el.inputmask._valueSet(""),
                opts.removeMaskOnSubmit && (el.inputmask._valueSet(el.inputmask.unmaskedvalue(), !0),
                setTimeout(function () {
                    writeBuffer(el, getBuffer());
                }, 0));
            }).on("reset", function () {
                setTimeout(function () {
                    $el.triggerHandler("setvalue.inputmask");
                }, 0);
            }), $el.on("mouseenter.inputmask", mouseenterEvent).on("blur.inputmask", blurEvent).on("focus.inputmask", focusEvent).on("mouseleave.inputmask", mouseleaveEvent).on("click.inputmask", clickEvent).on("dblclick.inputmask", dblclickEvent).on(PasteEventType + ".inputmask dragdrop.inputmask drop.inputmask", pasteEvent).on("cut.inputmask", cutEvent).on("complete.inputmask", opts.oncomplete).on("incomplete.inputmask", opts.onincomplete).on("cleared.inputmask", opts.oncleared).on("keydown.inputmask", keydownEvent).on("keypress.inputmask", keypressEvent),
            androidfirefox || $el.on("compositionstart.inputmask", compositionStartEvent).on("compositionupdate.inputmask", compositionUpdateEvent).on("compositionend.inputmask", compositionEndEvent),
            "paste" === PasteEventType && $el.on("input.inputmask", inputFallBackEvent)), $el.on("setvalue.inputmask", setValueEvent),
            patchValueProperty(el);
            var initialValue = $.isFunction(opts.onBeforeMask) ? opts.onBeforeMask.call(el, el.inputmask._valueGet(), opts) || el.inputmask._valueGet() : el.inputmask._valueGet();
            checkVal(el, !0, !1, initialValue.split(""));
            var buffer = getBuffer().slice();
            undoValue = buffer.join("");
            var activeElement;
            try {
                activeElement = document.activeElement;
            } catch (e) { }
            isComplete(buffer) === !1 && opts.clearIncomplete && resetMaskSet(), opts.clearMaskOnLostFocus && (buffer.join("") === getBufferTemplate().join("") ? buffer = [] : clearOptionalTail(buffer)),
            writeBuffer(el, buffer), activeElement === el && caret(el, seekNext(getLastValidPosition())),
            installEventRuler(el);
        }
        var undoValue, compositionCaretPos, compositionData, el, $el, maxLength, valueBuffer, isRTL = !1, skipKeyPressEvent = !1, skipInputEvent = !1, ignorable = !1, mouseEnter = !0;
        if (void 0 !== actionObj) switch (actionObj.action) {
            case "isComplete":
                return el = actionObj.el, $el = $(el), maskset = el.inputmask.maskset, opts = el.inputmask.opts,
                isComplete(actionObj.buffer);

            case "unmaskedvalue":
                return el = actionObj.el, void 0 === el ? ($el = $({}), el = $el[0], el.inputmask = new Inputmask(),
                el.inputmask.opts = opts, el.inputmask.el = el, el.inputmask.maskset = maskset,
                el.inputmask.isRTL = opts.numericInput, opts.numericInput && (isRTL = !0), valueBuffer = ($.isFunction(opts.onBeforeMask) ? opts.onBeforeMask.call($el, actionObj.value, opts) || actionObj.value : actionObj.value).split(""),
                checkVal(el, !1, !1, isRTL ? valueBuffer.reverse() : valueBuffer), $.isFunction(opts.onBeforeWrite) && opts.onBeforeWrite.call(this, void 0, getBuffer(), 0, opts)) : $el = $(el),
                maskset = el.inputmask.maskset, opts = el.inputmask.opts, isRTL = el.inputmask.isRTL,
                unmaskedvalue(el);

            case "mask":
                undoValue = getBuffer().join(""), mask(actionObj.el);
                break;

            case "format":
                return $el = $({}), $el[0].inputmask = new Inputmask(), $el[0].inputmask.opts = opts,
                $el[0].inputmask.el = $el[0], $el[0].inputmask.maskset = maskset, $el[0].inputmask.isRTL = opts.numericInput,
                opts.numericInput && (isRTL = !0), valueBuffer = ($.isFunction(opts.onBeforeMask) ? opts.onBeforeMask.call($el, actionObj.value, opts) || actionObj.value : actionObj.value).split(""),
                checkVal(el, !1, !1, isRTL ? valueBuffer.reverse() : valueBuffer), $.isFunction(opts.onBeforeWrite) && opts.onBeforeWrite.call(this, void 0, getBuffer(), 0, opts),
                actionObj.metadata ? {
                    value: isRTL ? getBuffer().slice().reverse().join("") : getBuffer().join(""),
                    metadata: $el.inputmask("getmetadata")
                } : isRTL ? getBuffer().slice().reverse().join("") : getBuffer().join("");

            case "isValid":
                $el = $({}), $el[0].inputmask = new Inputmask(), $el[0].inputmask.opts = opts, $el[0].inputmask.el = $el[0],
                $el[0].inputmask.maskset = maskset, $el[0].inputmask.isRTL = opts.numericInput,
                opts.numericInput && (isRTL = !0), valueBuffer = actionObj.value.split(""), checkVal(el, !1, !0, isRTL ? valueBuffer.reverse() : valueBuffer);
                for (var buffer = getBuffer(), rl = determineLastRequiredPosition(), lmib = buffer.length - 1; lmib > rl && !isMask(lmib) ; lmib--);
                return buffer.splice(rl, lmib + 1 - rl), isComplete(buffer) && actionObj.value === buffer.join("");

            case "getemptymask":
                return el = actionObj.el, $el = $(el), maskset = el.inputmask.maskset, opts = el.inputmask.opts,
                getBufferTemplate();

            case "remove":
                el = actionObj.el, $el = $(el), maskset = el.inputmask.maskset, opts = el.inputmask.opts,
                el.inputmask._valueSet(unmaskedvalue($el)), $el.off(".inputmask");
                var valueProperty;
                Object.getOwnPropertyDescriptor && (valueProperty = Object.getOwnPropertyDescriptor(el, "value")),
                valueProperty && valueProperty.get ? el.inputmask.__valueGet && Object.defineProperty(el, "value", {
                    get: el.inputmask.__valueGet,
                    set: el.inputmask.__valueSet
                }) : document.__lookupGetter__ && el.__lookupGetter__("value") && el.inputmask.__valueGet && (el.__defineGetter__("value", el.inputmask.__valueGet),
                el.__defineSetter__("value", el.inputmask.__valueSet)), el.inputmask = void 0;
                break;

            case "getmetadata":
                if (el = actionObj.el, $el = $(el), maskset = el.inputmask.maskset, opts = el.inputmask.opts,
                $.isArray(maskset.metadata)) {
                    for (var alternation, lvp = getLastValidPosition(), firstAlt = lvp; firstAlt >= 0; firstAlt--) if (getMaskSet().validPositions[firstAlt] && void 0 !== getMaskSet().validPositions[firstAlt].alternation) {
                        alternation = getMaskSet().validPositions[firstAlt].alternation;
                        break;
                    }
                    return void 0 !== alternation ? maskset.metadata[getMaskSet().validPositions[lvp].locator[alternation]] : maskset.metadata[0];
                }
                return maskset.metadata;
        }
    }
    Inputmask.prototype = {
        defaults: {
            placeholder: "_",
            optionalmarker: {
                start: "[",
                end: "]"
            },
            quantifiermarker: {
                start: "{",
                end: "}"
            },
            groupmarker: {
                start: "(",
                end: ")"
            },
            alternatormarker: "|",
            escapeChar: "\\",
            mask: null,
            oncomplete: $.noop,
            onincomplete: $.noop,
            oncleared: $.noop,
            repeat: 0,
            greedy: !0,
            autoUnmask: !1,
            removeMaskOnSubmit: !1,
            clearMaskOnLostFocus: !0,
            insertMode: !0,
            clearIncomplete: !1,
            aliases: {},
            alias: null,
            onKeyDown: $.noop,
            onBeforeMask: null,
            onBeforePaste: function (pastedValue, opts) {
                return $.isFunction(opts.onBeforeMask) ? opts.onBeforeMask(pastedValue, opts) : pastedValue;
            },
            onBeforeWrite: null,
            onUnMask: null,
            showMaskOnFocus: !0,
            showMaskOnHover: !0,
            onKeyValidation: $.noop,
            skipOptionalPartCharacter: " ",
            showTooltip: !1,
            numericInput: !1,
            rightAlign: !1,
            undoOnEscape: !0,
            radixPoint: "",
            groupSeparator: "",
            radixFocus: !1,
            nojumps: !1,
            nojumpsThreshold: 0,
            keepStatic: null,
            positionCaretOnTab: !1,
            tabThrough: !1,
            supportsInputType: [],
            definitions: {
                "9": {
                    validator: "[0-9]",
                    cardinality: 1,
                    definitionSymbol: "*"
                },
                a: {
                    validator: "[A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",
                    cardinality: 1,
                    definitionSymbol: "*"
                },
                "*": {
                    validator: "[0-9A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",
                    cardinality: 1
                }
            },
            ignorables: [8, 9, 13, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40, 45, 46, 93, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123],
            isComplete: null,
            canClearPosition: $.noop,
            postValidation: null
        },
        masksCache: {},
        mask: function (el) {
            var scopedOpts = $.extend(!0, {}, this.opts);
            importAttributeOptions(el, scopedOpts, $.extend(!0, {}, this.userOptions));
            var maskset = generateMaskSet(scopedOpts, this.noMasksCache);
            return void 0 !== maskset && (el.inputmask = el.inputmask || new Inputmask(), el.inputmask.opts = scopedOpts,
            el.inputmask.noMasksCache = this.noMasksCache, el.inputmask.userOptions = $.extend(!0, {}, this.userOptions),
            el.inputmask.el = el, el.inputmask.maskset = maskset, el.inputmask.isRTL = !1, $.data(el, "_inputmask_opts", scopedOpts),
            maskScope({
                action: "mask",
                el: el
            }, maskset, el.inputmask.opts)), el;
        },
        option: function (options) {
            return "string" == typeof options ? this.opts[options] : "object" == typeof options ? ($.extend(this.opts, options),
            $.extend(this.userOptions, options), this) : void 0;
        },
        unmaskedvalue: function () {
            return this.el ? maskScope({
                action: "unmaskedvalue",
                el: this.el
            }) : void 0;
        },
        remove: function () {
            return this.el ? (maskScope({
                action: "remove",
                el: this.el
            }), this.el.inputmask = void 0, this.el) : void 0;
        },
        getemptymask: function () {
            return this.el ? maskScope({
                action: "getemptymask",
                el: this.el
            }) : void 0;
        },
        hasMaskedValue: function () {
            return !this.opts.autoUnmask;
        },
        isComplete: function () {
            return this.el ? maskScope({
                action: "isComplete",
                buffer: this.el.inputmask._valueGet().split(""),
                el: this.el
            }) : void 0;
        },
        getmetadata: function () {
            return this.el ? maskScope({
                action: "getmetadata",
                el: this.el
            }) : void 0;
        }
    }, Inputmask.extendDefaults = function (options) {
        $.extend(Inputmask.prototype.defaults, options);
    }, Inputmask.extendDefinitions = function (definition) {
        $.extend(Inputmask.prototype.defaults.definitions, definition);
    }, Inputmask.extendAliases = function (alias) {
        $.extend(Inputmask.prototype.defaults.aliases, alias);
    }, Inputmask.format = function (value, options, metadata) {
        var opts = $.extend(!0, {}, Inputmask.prototype.defaults, options);
        return resolveAlias(opts.alias, options, opts), maskScope({
            action: "format",
            value: value,
            metadata: metadata
        }, generateMaskSet(opts, options && void 0 !== options.definitions), opts);
    }, Inputmask.unmask = function (value, options) {
        var opts = $.extend(!0, {}, Inputmask.prototype.defaults, options);
        return resolveAlias(opts.alias, options, opts), maskScope({
            action: "unmaskedvalue",
            value: value
        }, generateMaskSet(opts, options && void 0 !== options.definitions), opts);
    }, Inputmask.isValid = function (value, options) {
        var opts = $.extend(!0, {}, Inputmask.prototype.defaults, options);
        return resolveAlias(opts.alias, options, opts), maskScope({
            action: "isValid",
            value: value
        }, generateMaskSet(opts, options && void 0 !== options.definitions), opts);
    }, Inputmask.escapeRegex = function (str) {
        var specials = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\", "$", "^"];
        return str.replace(new RegExp("(\\" + specials.join("|\\") + ")", "gim"), "\\$1");
    }, Inputmask.keyCode = {
        ALT: 18,
        BACKSPACE: 8,
        CAPS_LOCK: 20,
        COMMA: 188,
        COMMAND: 91,
        COMMAND_LEFT: 91,
        COMMAND_RIGHT: 93,
        CONTROL: 17,
        DELETE: 46,
        DOWN: 40,
        END: 35,
        ENTER: 13,
        ESCAPE: 27,
        HOME: 36,
        INSERT: 45,
        LEFT: 37,
        MENU: 93,
        NUMPAD_ADD: 107,
        NUMPAD_DECIMAL: 110,
        NUMPAD_DIVIDE: 111,
        NUMPAD_ENTER: 108,
        NUMPAD_MULTIPLY: 106,
        NUMPAD_SUBTRACT: 109,
        PAGE_DOWN: 34,
        PAGE_UP: 33,
        PERIOD: 190,
        RIGHT: 39,
        SHIFT: 16,
        SPACE: 32,
        TAB: 9,
        UP: 38,
        WINDOWS: 91
    };
    var ua = navigator.userAgent, iphone = null !== ua.match(new RegExp("iphone", "i")), androidchrome = null !== ua.match(new RegExp("android.*chrome.*", "i")), androidfirefox = null !== ua.match(new RegExp("android.*firefox.*", "i")), PasteEventType = isInputEventSupported("paste") ? "paste" : isInputEventSupported("input") ? "input" : "propertychange";
    return window.Inputmask = Inputmask, Inputmask;
}(jQuery), function ($, Inputmask) {
    return void 0 === $.fn.inputmask && ($.fn.inputmask = function (fn, options) {
        var nptmask, input;
        if (options = options || {}, "string" == typeof fn) switch (fn) {
            case "mask":
                return nptmask = new Inputmask(options), this.each(function () {
                    nptmask.mask(this);
                });

            case "unmaskedvalue":
                return input = this.jquery && this.length > 0 ? this[0] : this, input.inputmask ? input.inputmask.unmaskedvalue() : $(input).val();

            case "remove":
                return this.each(function () {
                    this.inputmask && this.inputmask.remove();
                });

            case "getemptymask":
                return input = this.jquery && this.length > 0 ? this[0] : this, input.inputmask ? input.inputmask.getemptymask() : "";

            case "hasMaskedValue":
                return input = this.jquery && this.length > 0 ? this[0] : this, input.inputmask ? input.inputmask.hasMaskedValue() : !1;

            case "isComplete":
                return input = this.jquery && this.length > 0 ? this[0] : this, input.inputmask ? input.inputmask.isComplete() : !0;

            case "getmetadata":
                return input = this.jquery && this.length > 0 ? this[0] : this, input.inputmask ? input.inputmask.getmetadata() : void 0;

            case "setvalue":
                input = this.jquery && this.length > 0 ? this[0] : this, $(input).val(options),
                void 0 !== input.inputmask && $(input).triggerHandler("setvalue.inputmask");
                break;

            case "option":
                if ("string" != typeof options) return this.each(function () {
                    return void 0 !== this.inputmask ? this.inputmask.option(options) : void 0;
                });
                if (input = this.jquery && this.length > 0 ? this[0] : this, void 0 !== input.inputmask) return input.inputmask.option(options);
                break;

            default:
                return options.alias = fn, nptmask = new Inputmask(options), this.each(function () {
                    nptmask.mask(this);
                });
        } else {
            if ("object" == typeof fn) return nptmask = new Inputmask(fn), this.each(void 0 === fn.mask && void 0 === fn.alias ? function () {
                return void 0 !== this.inputmask ? this.inputmask.option(fn) : void nptmask.mask(this);
            } : function () {
                nptmask.mask(this);
            });
            if (void 0 === fn) return this.each(function () {
                nptmask = new Inputmask(options), nptmask.mask(this);
            });
        }
    }), $.fn.inputmask;
}(jQuery, Inputmask), function ($, Inputmask) {
    return Inputmask.extendDefinitions({
        h: {
            validator: "[01][0-9]|2[0-3]",
            cardinality: 2,
            prevalidator: [{
                validator: "[0-2]",
                cardinality: 1
            }]
        },
        s: {
            validator: "[0-5][0-9]",
            cardinality: 2,
            prevalidator: [{
                validator: "[0-5]",
                cardinality: 1
            }]
        },
        d: {
            validator: "0[1-9]|[12][0-9]|3[01]",
            cardinality: 2,
            prevalidator: [{
                validator: "[0-3]",
                cardinality: 1
            }]
        },
        m: {
            validator: "0[1-9]|1[012]",
            cardinality: 2,
            prevalidator: [{
                validator: "[01]",
                cardinality: 1
            }]
        },
        y: {
            validator: "(19|20)\\d{2}",
            cardinality: 4,
            prevalidator: [{
                validator: "[12]",
                cardinality: 1
            }, {
                validator: "(19|20)",
                cardinality: 2
            }, {
                validator: "(19|20)\\d",
                cardinality: 3
            }]
        }
    }), Inputmask.extendAliases({
        "dd/mm/yyyy": {
            mask: "1/2/y",
            placeholder: "dd/mm/yyyy",
            regex: {
                val1pre: new RegExp("[0-3]"),
                val1: new RegExp("0[1-9]|[12][0-9]|3[01]"),
                val2pre: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[1-9]|[12][0-9]|3[01])" + escapedSeparator + "[01])");
                },
                val2: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[1-9]|[12][0-9])" + escapedSeparator + "(0[1-9]|1[012]))|(30" + escapedSeparator + "(0[13-9]|1[012]))|(31" + escapedSeparator + "(0[13578]|1[02]))");
                }
            },
            leapday: "29/02/",
            separator: "/",
            yearrange: {
                minyear: 1900,
                maxyear: 2099
            },
            isInYearRange: function (chrs, minyear, maxyear) {
                if (isNaN(chrs)) return !1;
                var enteredyear = parseInt(chrs.concat(minyear.toString().slice(chrs.length))), enteredyear2 = parseInt(chrs.concat(maxyear.toString().slice(chrs.length)));
                return (isNaN(enteredyear) ? !1 : enteredyear >= minyear && maxyear >= enteredyear) || (isNaN(enteredyear2) ? !1 : enteredyear2 >= minyear && maxyear >= enteredyear2);
            },
            determinebaseyear: function (minyear, maxyear, hint) {
                var currentyear = new Date().getFullYear();
                if (minyear > currentyear) return minyear;
                if (currentyear > maxyear) {
                    for (var maxYearPrefix = maxyear.toString().slice(0, 2), maxYearPostfix = maxyear.toString().slice(2, 4) ; maxYearPrefix + hint > maxyear;) maxYearPrefix--;
                    var maxxYear = maxYearPrefix + maxYearPostfix;
                    return minyear > maxxYear ? minyear : maxxYear;
                }
                return currentyear;
            },
            onKeyDown: function (e, buffer, caretPos, opts) {
                var $input = $(this);
                if (e.ctrlKey && e.keyCode === Inputmask.keyCode.RIGHT) {
                    var today = new Date();
                    $input.val(today.getDate().toString() + (today.getMonth() + 1).toString() + today.getFullYear().toString()),
                    $input.triggerHandler("setvalue.inputmask");
                }
            },
            getFrontValue: function (mask, buffer, opts) {
                for (var start = 0, length = 0, i = 0; i < mask.length && "2" !== mask.charAt(i) ; i++) {
                    var definition = opts.definitions[mask.charAt(i)];
                    definition ? (start += length, length = definition.cardinality) : length++;
                }
                return buffer.join("").substr(start, length);
            },
            definitions: {
                "1": {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        var isValid = opts.regex.val1.test(chrs);
                        return strict || isValid || chrs.charAt(1) !== opts.separator && -1 === "-./".indexOf(chrs.charAt(1)) || !(isValid = opts.regex.val1.test("0" + chrs.charAt(0))) ? isValid : (maskset.buffer[pos - 1] = "0",
                        {
                            refreshFromBuffer: {
                                start: pos - 1,
                                end: pos
                            },
                            pos: pos,
                            c: chrs.charAt(0)
                        });
                    },
                    cardinality: 2,
                    prevalidator: [{
                        validator: function (chrs, maskset, pos, strict, opts) {
                            var pchrs = chrs;
                            isNaN(maskset.buffer[pos + 1]) || (pchrs += maskset.buffer[pos + 1]);
                            var isValid = 1 === pchrs.length ? opts.regex.val1pre.test(pchrs) : opts.regex.val1.test(pchrs);
                            if (!strict && !isValid) {
                                if (isValid = opts.regex.val1.test(chrs + "0")) return maskset.buffer[pos] = chrs,
                                maskset.buffer[++pos] = "0", {
                                    pos: pos,
                                    c: "0"
                                };
                                if (isValid = opts.regex.val1.test("0" + chrs)) return maskset.buffer[pos] = "0",
                                pos++, {
                                    pos: pos
                                };
                            }
                            return isValid;
                        },
                        cardinality: 1
                    }]
                },
                "2": {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        var frontValue = opts.getFrontValue(maskset.mask, maskset.buffer, opts);
                        -1 !== frontValue.indexOf(opts.placeholder[0]) && (frontValue = "01" + opts.separator);
                        var isValid = opts.regex.val2(opts.separator).test(frontValue + chrs);
                        if (!strict && !isValid && (chrs.charAt(1) === opts.separator || -1 !== "-./".indexOf(chrs.charAt(1))) && (isValid = opts.regex.val2(opts.separator).test(frontValue + "0" + chrs.charAt(0)))) return maskset.buffer[pos - 1] = "0",
                        {
                            refreshFromBuffer: {
                                start: pos - 1,
                                end: pos
                            },
                            pos: pos,
                            c: chrs.charAt(0)
                        };
                        if (opts.mask.indexOf("2") === opts.mask.length - 1 && isValid) {
                            var dayMonthValue = maskset.buffer.join("").substr(4, 4) + chrs;
                            if (dayMonthValue !== opts.leapday) return !0;
                            var year = parseInt(maskset.buffer.join("").substr(0, 4), 10);
                            return year % 4 === 0 ? year % 100 === 0 ? year % 400 === 0 ? !0 : !1 : !0 : !1;
                        }
                        return isValid;
                    },
                    cardinality: 2,
                    prevalidator: [{
                        validator: function (chrs, maskset, pos, strict, opts) {
                            isNaN(maskset.buffer[pos + 1]) || (chrs += maskset.buffer[pos + 1]);
                            var frontValue = opts.getFrontValue(maskset.mask, maskset.buffer, opts);
                            -1 !== frontValue.indexOf(opts.placeholder[0]) && (frontValue = "01" + opts.separator);
                            var isValid = 1 === chrs.length ? opts.regex.val2pre(opts.separator).test(frontValue + chrs) : opts.regex.val2(opts.separator).test(frontValue + chrs);
                            return strict || isValid || !(isValid = opts.regex.val2(opts.separator).test(frontValue + "0" + chrs)) ? isValid : (maskset.buffer[pos] = "0",
                            pos++, {
                                pos: pos
                            });
                        },
                        cardinality: 1
                    }]
                },
                y: {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        if (opts.isInYearRange(chrs, opts.yearrange.minyear, opts.yearrange.maxyear)) {
                            var dayMonthValue = maskset.buffer.join("").substr(0, 6);
                            if (dayMonthValue !== opts.leapday) return !0;
                            var year = parseInt(chrs, 10);
                            return year % 4 === 0 ? year % 100 === 0 ? year % 400 === 0 ? !0 : !1 : !0 : !1;
                        }
                        return !1;
                    },
                    cardinality: 4,
                    prevalidator: [{
                        validator: function (chrs, maskset, pos, strict, opts) {
                            var isValid = opts.isInYearRange(chrs, opts.yearrange.minyear, opts.yearrange.maxyear);
                            if (!strict && !isValid) {
                                var yearPrefix = opts.determinebaseyear(opts.yearrange.minyear, opts.yearrange.maxyear, chrs + "0").toString().slice(0, 1);
                                if (isValid = opts.isInYearRange(yearPrefix + chrs, opts.yearrange.minyear, opts.yearrange.maxyear)) return maskset.buffer[pos++] = yearPrefix.charAt(0),
                                {
                                    pos: pos
                                };
                                if (yearPrefix = opts.determinebaseyear(opts.yearrange.minyear, opts.yearrange.maxyear, chrs + "0").toString().slice(0, 2),
                                isValid = opts.isInYearRange(yearPrefix + chrs, opts.yearrange.minyear, opts.yearrange.maxyear)) return maskset.buffer[pos++] = yearPrefix.charAt(0),
                                maskset.buffer[pos++] = yearPrefix.charAt(1), {
                                    pos: pos
                                };
                            }
                            return isValid;
                        },
                        cardinality: 1
                    }, {
                        validator: function (chrs, maskset, pos, strict, opts) {
                            var isValid = opts.isInYearRange(chrs, opts.yearrange.minyear, opts.yearrange.maxyear);
                            if (!strict && !isValid) {
                                var yearPrefix = opts.determinebaseyear(opts.yearrange.minyear, opts.yearrange.maxyear, chrs).toString().slice(0, 2);
                                if (isValid = opts.isInYearRange(chrs[0] + yearPrefix[1] + chrs[1], opts.yearrange.minyear, opts.yearrange.maxyear)) return maskset.buffer[pos++] = yearPrefix.charAt(1),
                                {
                                    pos: pos
                                };
                                if (yearPrefix = opts.determinebaseyear(opts.yearrange.minyear, opts.yearrange.maxyear, chrs).toString().slice(0, 2),
                                opts.isInYearRange(yearPrefix + chrs, opts.yearrange.minyear, opts.yearrange.maxyear)) {
                                    var dayMonthValue = maskset.buffer.join("").substr(0, 6);
                                    if (dayMonthValue !== opts.leapday) isValid = !0; else {
                                        var year = parseInt(chrs, 10);
                                        isValid = year % 4 === 0 ? year % 100 === 0 ? year % 400 === 0 ? !0 : !1 : !0 : !1;
                                    }
                                } else isValid = !1;
                                if (isValid) return maskset.buffer[pos - 1] = yearPrefix.charAt(0), maskset.buffer[pos++] = yearPrefix.charAt(1),
                                maskset.buffer[pos++] = chrs.charAt(0), {
                                    refreshFromBuffer: {
                                        start: pos - 3,
                                        end: pos
                                    },
                                    pos: pos
                                };
                            }
                            return isValid;
                        },
                        cardinality: 2
                    }, {
                        validator: function (chrs, maskset, pos, strict, opts) {
                            return opts.isInYearRange(chrs, opts.yearrange.minyear, opts.yearrange.maxyear);
                        },
                        cardinality: 3
                    }]
                }
            },
            insertMode: !1,
            autoUnmask: !1
        },
        "mm/dd/yyyy": {
            placeholder: "mm/dd/yyyy",
            alias: "dd/mm/yyyy",
            regex: {
                val2pre: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[13-9]|1[012])" + escapedSeparator + "[0-3])|(02" + escapedSeparator + "[0-2])");
                },
                val2: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[1-9]|1[012])" + escapedSeparator + "(0[1-9]|[12][0-9]))|((0[13-9]|1[012])" + escapedSeparator + "30)|((0[13578]|1[02])" + escapedSeparator + "31)");
                },
                val1pre: new RegExp("[01]"),
                val1: new RegExp("0[1-9]|1[012]")
            },
            leapday: "02/29/",
            onKeyDown: function (e, buffer, caretPos, opts) {
                var $input = $(this);
                if (e.ctrlKey && e.keyCode === Inputmask.keyCode.RIGHT) {
                    var today = new Date();
                    $input.val((today.getMonth() + 1).toString() + today.getDate().toString() + today.getFullYear().toString()),
                    $input.triggerHandler("setvalue.inputmask");
                }
            }
        },
        "yyyy/mm/dd": {
            mask: "y/1/2",
            placeholder: "yyyy/mm/dd",
            alias: "mm/dd/yyyy",
            leapday: "/02/29",
            onKeyDown: function (e, buffer, caretPos, opts) {
                var $input = $(this);
                if (e.ctrlKey && e.keyCode === Inputmask.keyCode.RIGHT) {
                    var today = new Date();
                    $input.val(today.getFullYear().toString() + (today.getMonth() + 1).toString() + today.getDate().toString()),
                    $input.triggerHandler("setvalue.inputmask");
                }
            }
        },
        "dd.mm.yyyy": {
            mask: "1.2.y",
            placeholder: "dd.mm.yyyy",
            leapday: "29.02.",
            separator: ".",
            alias: "dd/mm/yyyy"
        },
        "dd-mm-yyyy": {
            mask: "1-2-y",
            placeholder: "dd-mm-yyyy",
            leapday: "29-02-",
            separator: "-",
            alias: "dd/mm/yyyy"
        },
        "mm.dd.yyyy": {
            mask: "1.2.y",
            placeholder: "mm.dd.yyyy",
            leapday: "02.29.",
            separator: ".",
            alias: "mm/dd/yyyy"
        },
        "mm-dd-yyyy": {
            mask: "1-2-y",
            placeholder: "mm-dd-yyyy",
            leapday: "02-29-",
            separator: "-",
            alias: "mm/dd/yyyy"
        },
        "yyyy.mm.dd": {
            mask: "y.1.2",
            placeholder: "yyyy.mm.dd",
            leapday: ".02.29",
            separator: ".",
            alias: "yyyy/mm/dd"
        },
        "yyyy-mm-dd": {
            mask: "y-1-2",
            placeholder: "yyyy-mm-dd",
            leapday: "-02-29",
            separator: "-",
            alias: "yyyy/mm/dd"
        },
        datetime: {
            mask: "1/2/y h:s",
            placeholder: "dd/mm/yyyy hh:mm",
            alias: "dd/mm/yyyy",
            regex: {
                hrspre: new RegExp("[012]"),
                hrs24: new RegExp("2[0-4]|1[3-9]"),
                hrs: new RegExp("[01][0-9]|2[0-4]"),
                ampm: new RegExp("^[a|p|A|P][m|M]"),
                mspre: new RegExp("[0-5]"),
                ms: new RegExp("[0-5][0-9]")
            },
            timeseparator: ":",
            hourFormat: "24",
            definitions: {
                h: {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        if ("24" === opts.hourFormat && 24 === parseInt(chrs, 10)) return maskset.buffer[pos - 1] = "0",
                        maskset.buffer[pos] = "0", {
                            refreshFromBuffer: {
                                start: pos - 1,
                                end: pos
                            },
                            c: "0"
                        };
                        var isValid = opts.regex.hrs.test(chrs);
                        if (!strict && !isValid && (chrs.charAt(1) === opts.timeseparator || -1 !== "-.:".indexOf(chrs.charAt(1))) && (isValid = opts.regex.hrs.test("0" + chrs.charAt(0)))) return maskset.buffer[pos - 1] = "0",
                        maskset.buffer[pos] = chrs.charAt(0), pos++, {
                            refreshFromBuffer: {
                                start: pos - 2,
                                end: pos
                            },
                            pos: pos,
                            c: opts.timeseparator
                        };
                        if (isValid && "24" !== opts.hourFormat && opts.regex.hrs24.test(chrs)) {
                            var tmp = parseInt(chrs, 10);
                            return 24 === tmp ? (maskset.buffer[pos + 5] = "a", maskset.buffer[pos + 6] = "m") : (maskset.buffer[pos + 5] = "p",
                            maskset.buffer[pos + 6] = "m"), tmp -= 12, 10 > tmp ? (maskset.buffer[pos] = tmp.toString(),
                            maskset.buffer[pos - 1] = "0") : (maskset.buffer[pos] = tmp.toString().charAt(1),
                            maskset.buffer[pos - 1] = tmp.toString().charAt(0)), {
                                refreshFromBuffer: {
                                    start: pos - 1,
                                    end: pos + 6
                                },
                                c: maskset.buffer[pos]
                            };
                        }
                        return isValid;
                    },
                    cardinality: 2,
                    prevalidator: [{
                        validator: function (chrs, maskset, pos, strict, opts) {
                            var isValid = opts.regex.hrspre.test(chrs);
                            return strict || isValid || !(isValid = opts.regex.hrs.test("0" + chrs)) ? isValid : (maskset.buffer[pos] = "0",
                            pos++, {
                                pos: pos
                            });
                        },
                        cardinality: 1
                    }]
                },
                s: {
                    validator: "[0-5][0-9]",
                    cardinality: 2,
                    prevalidator: [{
                        validator: function (chrs, maskset, pos, strict, opts) {
                            var isValid = opts.regex.mspre.test(chrs);
                            return strict || isValid || !(isValid = opts.regex.ms.test("0" + chrs)) ? isValid : (maskset.buffer[pos] = "0",
                            pos++, {
                                pos: pos
                            });
                        },
                        cardinality: 1
                    }]
                },
                t: {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        return opts.regex.ampm.test(chrs + "m");
                    },
                    casing: "lower",
                    cardinality: 1
                }
            },
            insertMode: !1,
            autoUnmask: !1
        },
        datetime12: {
            mask: "1/2/y h:s t\\m",
            placeholder: "dd/mm/yyyy hh:mm xm",
            alias: "datetime",
            hourFormat: "12"
        },
        "mm/dd/yyyy hh:mm xm": {
            mask: "1/2/y h:s t\\m",
            placeholder: "mm/dd/yyyy hh:mm xm",
            alias: "datetime12",
            regex: {
                val2pre: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[13-9]|1[012])" + escapedSeparator + "[0-3])|(02" + escapedSeparator + "[0-2])");
                },
                val2: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[1-9]|1[012])" + escapedSeparator + "(0[1-9]|[12][0-9]))|((0[13-9]|1[012])" + escapedSeparator + "30)|((0[13578]|1[02])" + escapedSeparator + "31)");
                },
                val1pre: new RegExp("[01]"),
                val1: new RegExp("0[1-9]|1[012]")
            },
            leapday: "02/29/",
            onKeyDown: function (e, buffer, caretPos, opts) {
                var $input = $(this);
                if (e.ctrlKey && e.keyCode === Inputmask.keyCode.RIGHT) {
                    var today = new Date();
                    $input.val((today.getMonth() + 1).toString() + today.getDate().toString() + today.getFullYear().toString()),
                    $input.triggerHandler("setvalue.inputmask");
                }
            }
        },
        "hh:mm t": {
            mask: "h:s t\\m",
            placeholder: "hh:mm xm",
            alias: "datetime",
            hourFormat: "12"
        },
        "h:s t": {
            mask: "h:s t\\m",
            placeholder: "hh:mm xm",
            alias: "datetime",
            hourFormat: "12"
        },
        "hh:mm:ss": {
            mask: "h:s:s",
            placeholder: "hh:mm:ss",
            alias: "datetime",
            autoUnmask: !1
        },
        "hh:mm": {
            mask: "h:s",
            placeholder: "hh:mm",
            alias: "datetime",
            autoUnmask: !1
        },
        date: {
            alias: "dd/mm/yyyy"
        },
        "mm/yyyy": {
            mask: "1/y",
            placeholder: "mm/yyyy",
            leapday: "donotuse",
            separator: "/",
            alias: "mm/dd/yyyy"
        },
        shamsi: {
            regex: {
                val2pre: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[1-9]|1[012])" + escapedSeparator + "[0-3])");
                },
                val2: function (separator) {
                    var escapedSeparator = Inputmask.escapeRegex.call(this, separator);
                    return new RegExp("((0[1-9]|1[012])" + escapedSeparator + "(0[1-9]|[12][0-9]))|((0[1-9]|1[012])" + escapedSeparator + "30)|((0[1-6])" + escapedSeparator + "31)");
                },
                val1pre: new RegExp("[01]"),
                val1: new RegExp("0[1-9]|1[012]")
            },
            yearrange: {
                minyear: 1300,
                maxyear: 1499
            },
            mask: "y/1/2",
            leapday: "/12/30",
            placeholder: "yyyy/mm/dd",
            alias: "mm/dd/yyyy",
            clearIncomplete: !0
        }
    }), Inputmask;
}(jQuery, Inputmask), function ($, Inputmask) {
    return Inputmask.extendDefinitions({
        A: {
            validator: "[A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",
            cardinality: 1,
            casing: "upper"
        },
        "&": {
            validator: "[0-9A-Za-z\u0410-\u044f\u0401\u0451\xc0-\xff\xb5]",
            cardinality: 1,
            casing: "upper"
        },
        "#": {
            validator: "[0-9A-Fa-f]",
            cardinality: 1,
            casing: "upper"
        }
    }), Inputmask.extendAliases({
        url: {
            mask: "ir",
            placeholder: "",
            separator: "",
            defaultPrefix: "http://",
            regex: {
                urlpre1: new RegExp("[fh]"),
                urlpre2: new RegExp("(ft|ht)"),
                urlpre3: new RegExp("(ftp|htt)"),
                urlpre4: new RegExp("(ftp:|http|ftps)"),
                urlpre5: new RegExp("(ftp:/|ftps:|http:|https)"),
                urlpre6: new RegExp("(ftp://|ftps:/|http:/|https:)"),
                urlpre7: new RegExp("(ftp://|ftps://|http://|https:/)"),
                urlpre8: new RegExp("(ftp://|ftps://|http://|https://)")
            },
            definitions: {
                i: {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        return !0;
                    },
                    cardinality: 8,
                    prevalidator: function () {
                        for (var result = [], prefixLimit = 8, i = 0; prefixLimit > i; i++) result[i] = function () {
                            var j = i;
                            return {
                                validator: function (chrs, maskset, pos, strict, opts) {
                                    if (opts.regex["urlpre" + (j + 1)]) {
                                        var k, tmp = chrs;
                                        j + 1 - chrs.length > 0 && (tmp = maskset.buffer.join("").substring(0, j + 1 - chrs.length) + "" + tmp);
                                        var isValid = opts.regex["urlpre" + (j + 1)].test(tmp);
                                        if (!strict && !isValid) {
                                            for (pos -= j, k = 0; k < opts.defaultPrefix.length; k++) maskset.buffer[pos] = opts.defaultPrefix[k],
                                            pos++;
                                            for (k = 0; k < tmp.length - 1; k++) maskset.buffer[pos] = tmp[k], pos++;
                                            return {
                                                pos: pos
                                            };
                                        }
                                        return isValid;
                                    }
                                    return !1;
                                },
                                cardinality: j
                            };
                        }();
                        return result;
                    }()
                },
                r: {
                    validator: ".",
                    cardinality: 50
                }
            },
            insertMode: !1,
            autoUnmask: !1
        },
        ip: {
            mask: "i[i[i]].i[i[i]].i[i[i]].i[i[i]]",
            definitions: {
                i: {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        return pos - 1 > -1 && "." !== maskset.buffer[pos - 1] ? (chrs = maskset.buffer[pos - 1] + chrs,
                        chrs = pos - 2 > -1 && "." !== maskset.buffer[pos - 2] ? maskset.buffer[pos - 2] + chrs : "0" + chrs) : chrs = "00" + chrs,
                        new RegExp("25[0-5]|2[0-4][0-9]|[01][0-9][0-9]").test(chrs);
                    },
                    cardinality: 1
                }
            }
        },
        email: {
            mask: "*{1,64}[.*{1,64}][.*{1,64}][.*{1,64}]@*{1,64}[.*{2,64}][.*{2,6}][.*{1,2}]",
            greedy: !1,
            onBeforePaste: function (pastedValue, opts) {
                return pastedValue = pastedValue.toLowerCase(), pastedValue.replace("mailto:", "");
            },
            definitions: {
                "*": {
                    validator: "[0-9A-Za-z!#$%&'*+/=?^_`{|}~-]",
                    cardinality: 1,
                    casing: "lower"
                }
            }
        },
        mac: {
            mask: "##:##:##:##:##:##"
        }
    }), Inputmask;
}(jQuery, Inputmask), function ($, Inputmask) {
    return Inputmask.extendAliases({
        numeric: {
            mask: function (opts) {
                function autoEscape(txt) {
                    for (var escapedTxt = "", i = 0; i < txt.length; i++) escapedTxt += opts.definitions[txt.charAt(i)] ? "\\" + txt.charAt(i) : txt.charAt(i);
                    return escapedTxt;
                }
                if (0 !== opts.repeat && isNaN(opts.integerDigits) && (opts.integerDigits = opts.repeat),
                opts.repeat = 0, opts.groupSeparator === opts.radixPoint && ("." === opts.radixPoint ? opts.groupSeparator = "," : "," === opts.radixPoint ? opts.groupSeparator = "." : opts.groupSeparator = ""),
                " " === opts.groupSeparator && (opts.skipOptionalPartCharacter = void 0), opts.autoGroup = opts.autoGroup && "" !== opts.groupSeparator,
                opts.autoGroup && ("string" == typeof opts.groupSize && isFinite(opts.groupSize) && (opts.groupSize = parseInt(opts.groupSize)),
                isFinite(opts.integerDigits))) {
                    var seps = Math.floor(opts.integerDigits / opts.groupSize), mod = opts.integerDigits % opts.groupSize;
                    opts.integerDigits = parseInt(opts.integerDigits) + (0 === mod ? seps - 1 : seps),
                    opts.integerDigits < 1 && (opts.integerDigits = "*");
                }
                opts.placeholder.length > 1 && (opts.placeholder = opts.placeholder.charAt(0)),
                opts.radixFocus = opts.radixFocus && "" !== opts.placeholder && opts.integerOptional === !0,
                opts.definitions[";"] = opts.definitions["~"], opts.definitions[";"].definitionSymbol = "~",
                opts.numericInput === !0 && (opts.radixFocus = !1, opts.digitsOptional = !1, isNaN(opts.digits) && (opts.digits = 2),
                opts.decimalProtect = !1);
                var mask = autoEscape(opts.prefix);
                return mask += "[+]", mask += opts.integerOptional === !0 ? "~{1," + opts.integerDigits + "}" : "~{" + opts.integerDigits + "}",
                void 0 !== opts.digits && (isNaN(opts.digits) || parseInt(opts.digits) > 0) && (mask += opts.digitsOptional ? "[" + (opts.decimalProtect ? ":" : opts.radixPoint) + ";{1," + opts.digits + "}]" : (opts.decimalProtect ? ":" : opts.radixPoint) + ";{" + opts.digits + "}"),
                "" !== opts.negationSymbol.back && (mask += "[-]"), mask += autoEscape(opts.suffix),
                opts.greedy = !1, mask;
            },
            placeholder: "",
            greedy: !1,
            digits: "*",
            digitsOptional: !0,
            radixPoint: ".",
            radixFocus: !0,
            groupSize: 3,
            groupSeparator: "",
            autoGroup: !1,
            allowPlus: !0,
            allowMinus: !0,
            negationSymbol: {
                front: "-",
                back: ""
            },
            integerDigits: "+",
            integerOptional: !0,
            prefix: "",
            suffix: "",
            rightAlign: !0,
            decimalProtect: !0,
            min: null,
            max: null,
            step: 1,
            insertMode: !0,
            autoUnmask: !1,
            unmaskAsNumber: !1,
            postFormat: function (buffer, pos, reformatOnly, opts) {
                opts.numericInput === !0 && (buffer = buffer.reverse(), isFinite(pos) && (pos = buffer.join("").length - pos - 1));
                var i, l, suffixStripped = !1;
                buffer.length >= opts.suffix.length && buffer.join("").indexOf(opts.suffix) === buffer.length - opts.suffix.length && (buffer.length = buffer.length - opts.suffix.length,
                suffixStripped = !0), pos = pos >= buffer.length ? buffer.length - 1 : pos < opts.prefix.length ? opts.prefix.length : pos;
                var needsRefresh = !1, charAtPos = buffer[pos];
                if ("" === opts.groupSeparator || opts.numericInput !== !0 && -1 !== $.inArray(opts.radixPoint, buffer) && pos > $.inArray(opts.radixPoint, buffer) || new RegExp("[" + Inputmask.escapeRegex(opts.negationSymbol.front) + "+]").test(charAtPos)) {
                    if (suffixStripped) for (i = 0, l = opts.suffix.length; l > i; i++) buffer.push(opts.suffix.charAt(i));
                    return {
                        pos: pos
                    };
                }
                var cbuf = buffer.slice();
                charAtPos === opts.groupSeparator && (cbuf.splice(pos--, 1), charAtPos = cbuf[pos]),
                reformatOnly ? charAtPos !== opts.radixPoint && (cbuf[pos] = "?") : cbuf.splice(pos, 0, "?");
                var bufVal = cbuf.join(""), bufValOrigin = bufVal;
                if (bufVal.length > 0 && opts.autoGroup || reformatOnly && -1 !== bufVal.indexOf(opts.groupSeparator)) {
                    var escapedGroupSeparator = Inputmask.escapeRegex(opts.groupSeparator);
                    needsRefresh = 0 === bufVal.indexOf(opts.groupSeparator), bufVal = bufVal.replace(new RegExp(escapedGroupSeparator, "g"), "");
                    var radixSplit = bufVal.split(opts.radixPoint);
                    if (bufVal = "" === opts.radixPoint ? bufVal : radixSplit[0], bufVal !== opts.prefix + "?0" && bufVal.length >= opts.groupSize + opts.prefix.length) for (var reg = new RegExp("([-+]?[\\d?]+)([\\d?]{" + opts.groupSize + "})") ; reg.test(bufVal) ;) bufVal = bufVal.replace(reg, "$1" + opts.groupSeparator + "$2"),
                    bufVal = bufVal.replace(opts.groupSeparator + opts.groupSeparator, opts.groupSeparator);
                    "" !== opts.radixPoint && radixSplit.length > 1 && (bufVal += opts.radixPoint + radixSplit[1]);
                }
                for (needsRefresh = bufValOrigin !== bufVal, buffer.length = bufVal.length, i = 0,
                l = bufVal.length; l > i; i++) buffer[i] = bufVal.charAt(i);
                var newPos = $.inArray("?", buffer);
                if (-1 === newPos && charAtPos === opts.radixPoint && (newPos = $.inArray(opts.radixPoint, buffer)),
                reformatOnly ? buffer[newPos] = charAtPos : buffer.splice(newPos, 1), !needsRefresh && suffixStripped) for (i = 0,
                l = opts.suffix.length; l > i; i++) buffer.push(opts.suffix.charAt(i));
                return newPos = opts.numericInput && isFinite(pos) ? buffer.join("").length - newPos - 1 : newPos,
                opts.numericInput && (buffer = buffer.reverse(), $.inArray(opts.radixPoint, buffer) < newPos && buffer.join("").length - opts.suffix.length !== newPos && (newPos -= 1)),
                {
                    pos: newPos,
                    refreshFromBuffer: needsRefresh,
                    buffer: buffer
                };
            },
            onBeforeWrite: function (e, buffer, caretPos, opts) {
                if (e && ("blur" === e.type || "checkval" === e.type)) {
                    var maskedValue = buffer.join(""), processValue = maskedValue.replace(opts.prefix, "");
                    if (processValue = processValue.replace(opts.suffix, ""), processValue = processValue.replace(new RegExp(Inputmask.escapeRegex(opts.groupSeparator), "g"), ""),
                    "," === opts.radixPoint && (processValue = processValue.replace(Inputmask.escapeRegex(opts.radixPoint), ".")),
                    isFinite(processValue) && isFinite(opts.min) && parseFloat(processValue) < parseFloat(opts.min)) return $.extend(!0, {
                        refreshFromBuffer: !0,
                        buffer: (opts.prefix + opts.min).split("")
                    }, opts.postFormat((opts.prefix + opts.min).split(""), 0, !0, opts));
                    if (opts.numericInput !== !0) {
                        var tmpBufSplit = "" !== opts.radixPoint ? buffer.join("").split(opts.radixPoint) : [buffer.join("")], matchRslt = tmpBufSplit[0].match(opts.regex.integerPart(opts)), matchRsltDigits = 2 === tmpBufSplit.length ? tmpBufSplit[1].match(opts.regex.integerNPart(opts)) : void 0;
                        if (matchRslt) {
                            matchRslt[0] !== opts.negationSymbol.front + "0" && matchRslt[0] !== opts.negationSymbol.front && "+" !== matchRslt[0] || void 0 !== matchRsltDigits && !matchRsltDigits[0].match(/^0+$/) || buffer.splice(matchRslt.index, 1);
                            var radixPosition = $.inArray(opts.radixPoint, buffer);
                            if (-1 !== radixPosition) {
                                if (isFinite(opts.digits) && !opts.digitsOptional) {
                                    for (var i = 1; i <= opts.digits; i++) (void 0 === buffer[radixPosition + i] || buffer[radixPosition + i] === opts.placeholder.charAt(0)) && (buffer[radixPosition + i] = "0");
                                    return {
                                        refreshFromBuffer: maskedValue !== buffer.join(""),
                                        buffer: buffer
                                    };
                                }
                                if (radixPosition === buffer.length - opts.suffix.length - 1) return buffer.splice(radixPosition, 1),
                                {
                                    refreshFromBuffer: !0,
                                    buffer: buffer
                                };
                            }
                        }
                    }
                }
                if (opts.autoGroup) {
                    var rslt = opts.postFormat(buffer, opts.numericInput ? caretPos : caretPos - 1, !0, opts);
                    return rslt.caret = caretPos <= opts.prefix.length ? rslt.pos : rslt.pos + 1, rslt;
                }
            },
            regex: {
                integerPart: function (opts) {
                    return new RegExp("[" + Inputmask.escapeRegex(opts.negationSymbol.front) + "+]?\\d+");
                },
                integerNPart: function (opts) {
                    return new RegExp("[\\d" + Inputmask.escapeRegex(opts.groupSeparator) + "]+");
                }
            },
            signHandler: function (chrs, maskset, pos, strict, opts) {
                if (!strict && opts.allowMinus && "-" === chrs || opts.allowPlus && "+" === chrs) {
                    var matchRslt = maskset.buffer.join("").match(opts.regex.integerPart(opts));
                    if (matchRslt && matchRslt[0].length > 0) return maskset.buffer[matchRslt.index] === ("-" === chrs ? "+" : opts.negationSymbol.front) ? "-" === chrs ? "" !== opts.negationSymbol.back ? {
                        pos: matchRslt.index,
                        c: opts.negationSymbol.front,
                        remove: matchRslt.index,
                        caret: pos,
                        insert: {
                            pos: maskset.buffer.length - opts.suffix.length - 1,
                            c: opts.negationSymbol.back
                        }
                    } : {
                        pos: matchRslt.index,
                        c: opts.negationSymbol.front,
                        remove: matchRslt.index,
                        caret: pos
                    } : "" !== opts.negationSymbol.back ? {
                        pos: matchRslt.index,
                        c: "+",
                        remove: [matchRslt.index, maskset.buffer.length - opts.suffix.length - 1],
                        caret: pos
                    } : {
                        pos: matchRslt.index,
                        c: "+",
                        remove: matchRslt.index,
                        caret: pos
                    } : maskset.buffer[matchRslt.index] === ("-" === chrs ? opts.negationSymbol.front : "+") ? "-" === chrs && "" !== opts.negationSymbol.back ? {
                        remove: [matchRslt.index, maskset.buffer.length - opts.suffix.length - 1],
                        caret: pos - 1
                    } : {
                        remove: matchRslt.index,
                        caret: pos - 1
                    } : "-" === chrs ? "" !== opts.negationSymbol.back ? {
                        pos: matchRslt.index,
                        c: opts.negationSymbol.front,
                        caret: pos + 1,
                        insert: {
                            pos: maskset.buffer.length - opts.suffix.length,
                            c: opts.negationSymbol.back
                        }
                    } : {
                        pos: matchRslt.index,
                        c: opts.negationSymbol.front,
                        caret: pos + 1
                    } : {
                        pos: matchRslt.index,
                        c: chrs,
                        caret: pos + 1
                    };
                }
                return !1;
            },
            radixHandler: function (chrs, maskset, pos, strict, opts) {
                if (!strict && (-1 !== $.inArray(chrs, [",", "."]) && (chrs = opts.radixPoint),
                chrs === opts.radixPoint && void 0 !== opts.digits && (isNaN(opts.digits) || parseInt(opts.digits) > 0))) {
                    var radixPos = $.inArray(opts.radixPoint, maskset.buffer), integerValue = maskset.buffer.join("").match(opts.regex.integerPart(opts));
                    if (-1 !== radixPos && maskset.validPositions[radixPos]) return maskset.validPositions[radixPos - 1] ? {
                        caret: radixPos + 1
                    } : {
                        pos: integerValue.index,
                        c: integerValue[0],
                        caret: radixPos + 1
                    };
                    if (!integerValue || "0" === integerValue[0] && integerValue.index + 1 !== pos) return maskset.buffer[integerValue ? integerValue.index : pos] = "0",
                    {
                        pos: (integerValue ? integerValue.index : pos) + 1,
                        c: opts.radixPoint
                    };
                }
                return !1;
            },
            leadingZeroHandler: function (chrs, maskset, pos, strict, opts) {
                if (opts.numericInput === !0) {
                    if ("0" === maskset.buffer[maskset.buffer.length - opts.prefix.length - 1]) return {
                        pos: pos,
                        remove: maskset.buffer.length - opts.prefix.length - 1
                    };
                } else {
                    var matchRslt = maskset.buffer.join("").match(opts.regex.integerNPart(opts)), radixPosition = $.inArray(opts.radixPoint, maskset.buffer);
                    if (matchRslt && !strict && (-1 === radixPosition || radixPosition >= pos)) if (0 === matchRslt[0].indexOf("0")) {
                        pos < opts.prefix.length && (pos = matchRslt.index);
                        var _radixPosition = $.inArray(opts.radixPoint, maskset._buffer), digitsMatch = maskset._buffer && maskset.buffer.slice(radixPosition).join("") === maskset._buffer.slice(_radixPosition).join("") || 0 === parseInt(maskset.buffer.slice(radixPosition + 1).join("")), integerMatch = maskset._buffer && maskset.buffer.slice(matchRslt.index, radixPosition).join("") === maskset._buffer.slice(opts.prefix.length, _radixPosition).join("") || "0" === maskset.buffer.slice(matchRslt.index, radixPosition).join("");
                        if (-1 === radixPosition || digitsMatch && integerMatch) return maskset.buffer.splice(matchRslt.index, 1),
                        pos = pos > matchRslt.index ? pos - 1 : matchRslt.index, {
                            pos: pos,
                            remove: matchRslt.index
                        };
                        if (matchRslt.index + 1 === pos || "0" === chrs) return maskset.buffer.splice(matchRslt.index, 1),
                        pos = matchRslt.index, {
                            pos: pos,
                            remove: matchRslt.index
                        };
                    } else if ("0" === chrs && pos <= matchRslt.index && matchRslt[0] !== opts.groupSeparator) return !1;
                }
                return !0;
            },
            postValidation: function (buffer, opts) {
                var isValid = !0, maskedValue = buffer.join(""), processValue = maskedValue.replace(opts.prefix, "");
                return processValue = processValue.replace(opts.suffix, ""), processValue = processValue.replace(new RegExp(Inputmask.escapeRegex(opts.groupSeparator), "g"), ""),
                "," === opts.radixPoint && (processValue = processValue.replace(Inputmask.escapeRegex(opts.radixPoint), ".")),
                processValue = processValue.replace(new RegExp("^" + Inputmask.escapeRegex(opts.negationSymbol.front)), "-"),
                processValue = processValue.replace(new RegExp(Inputmask.escapeRegex(opts.negationSymbol.back) + "$"), ""),
                processValue = processValue === opts.negationSymbol.front ? processValue + "0" : processValue,
                isFinite(processValue) && (null !== opts.max && isFinite(opts.max) && (isValid = parseFloat(processValue) <= parseFloat(opts.max)),
                isValid && null !== opts.min && isFinite(opts.min) && (0 >= processValue || processValue.toString().length >= opts.min.toString().length) && (isValid = parseFloat(processValue) >= parseFloat(opts.min),
                isValid || (isValid = $.extend(!0, {
                    refreshFromBuffer: !0,
                    buffer: (opts.prefix + opts.min).split("")
                }, opts.postFormat((opts.prefix + opts.min).split(""), 0, !0, opts)), isValid.refreshFromBuffer = !0))),
                isValid;
            },
            definitions: {
                "~": {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        var isValid = opts.signHandler(chrs, maskset, pos, strict, opts);
                        if (!isValid && (isValid = opts.radixHandler(chrs, maskset, pos, strict, opts),
                        !isValid && (isValid = strict ? new RegExp("[0-9" + Inputmask.escapeRegex(opts.groupSeparator) + "]").test(chrs) : new RegExp("[0-9]").test(chrs),
                        isValid === !0 && (isValid = opts.leadingZeroHandler(chrs, maskset, pos, strict, opts),
                        isValid === !0)))) {
                            var radixPosition = $.inArray(opts.radixPoint, maskset.buffer);
                            isValid = -1 !== radixPosition && opts.digitsOptional === !1 && opts.numericInput !== !0 && pos > radixPosition && !strict ? {
                                pos: pos,
                                remove: pos
                            } : {
                                pos: pos
                            };
                        }
                        return isValid;
                    },
                    cardinality: 1,
                    prevalidator: null
                },
                "+": {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        var isValid = opts.signHandler(chrs, maskset, pos, strict, opts);
                        return !isValid && (strict && opts.allowMinus && chrs === opts.negationSymbol.front || opts.allowMinus && "-" === chrs || opts.allowPlus && "+" === chrs) && (isValid = "-" === chrs ? "" !== opts.negationSymbol.back ? {
                            pos: pos,
                            c: "-" === chrs ? opts.negationSymbol.front : "+",
                            caret: pos + 1,
                            insert: {
                                pos: maskset.buffer.length,
                                c: opts.negationSymbol.back
                            }
                        } : {
                            pos: pos,
                            c: "-" === chrs ? opts.negationSymbol.front : "+",
                            caret: pos + 1
                        } : !0), isValid;
                    },
                    cardinality: 1,
                    prevalidator: null,
                    placeholder: ""
                },
                "-": {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        var isValid = opts.signHandler(chrs, maskset, pos, strict, opts);
                        return !isValid && strict && opts.allowMinus && chrs === opts.negationSymbol.back && (isValid = !0),
                        isValid;
                    },
                    cardinality: 1,
                    prevalidator: null,
                    placeholder: ""
                },
                ":": {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        var isValid = opts.signHandler(chrs, maskset, pos, strict, opts);
                        if (!isValid) {
                            var radix = "[" + Inputmask.escapeRegex(opts.radixPoint) + ",\\.]";
                            isValid = new RegExp(radix).test(chrs), isValid && maskset.validPositions[pos] && maskset.validPositions[pos].match.placeholder === opts.radixPoint && (isValid = {
                                caret: pos + 1
                            });
                        }
                        return isValid ? {
                            c: opts.radixPoint
                        } : isValid;
                    },
                    cardinality: 1,
                    prevalidator: null,
                    placeholder: function (opts) {
                        return opts.radixPoint;
                    }
                }
            },
            onUnMask: function (maskedValue, unmaskedValue, opts) {
                var processValue = maskedValue.replace(opts.prefix, "");
                return processValue = processValue.replace(opts.suffix, ""), processValue = processValue.replace(new RegExp(Inputmask.escapeRegex(opts.groupSeparator), "g"), ""),
                opts.unmaskAsNumber ? (processValue = processValue.replace(Inputmask.escapeRegex.call(this, opts.radixPoint), "."),
                Number(processValue)) : processValue;
            },
            isComplete: function (buffer, opts) {
                var maskedValue = buffer.join(""), bufClone = buffer.slice();
                if (opts.postFormat(bufClone, 0, !0, opts), bufClone.join("") !== maskedValue) return !1;
                var processValue = maskedValue.replace(opts.prefix, "");
                return processValue = processValue.replace(opts.suffix, ""), processValue = processValue.replace(new RegExp(Inputmask.escapeRegex(opts.groupSeparator), "g"), ""),
                "," === opts.radixPoint && (processValue = processValue.replace(Inputmask.escapeRegex(opts.radixPoint), ".")),
                isFinite(processValue);
            },
            onBeforeMask: function (initialValue, opts) {
                if ("" !== opts.radixPoint && isFinite(initialValue)) initialValue = initialValue.toString().replace(".", opts.radixPoint); else {
                    var kommaMatches = initialValue.match(/,/g), dotMatches = initialValue.match(/\./g);
                    dotMatches && kommaMatches ? dotMatches.length > kommaMatches.length ? (initialValue = initialValue.replace(/\./g, ""),
                    initialValue = initialValue.replace(",", opts.radixPoint)) : kommaMatches.length > dotMatches.length ? (initialValue = initialValue.replace(/,/g, ""),
                    initialValue = initialValue.replace(".", opts.radixPoint)) : initialValue = initialValue.indexOf(".") < initialValue.indexOf(",") ? initialValue.replace(/\./g, "") : initialValue = initialValue.replace(/,/g, "") : initialValue = initialValue.replace(new RegExp(Inputmask.escapeRegex(opts.groupSeparator), "g"), "");
                }
                if (0 === opts.digits && (-1 !== initialValue.indexOf(".") ? initialValue = initialValue.substring(0, initialValue.indexOf(".")) : -1 !== initialValue.indexOf(",") && (initialValue = initialValue.substring(0, initialValue.indexOf(",")))),
                "" !== opts.radixPoint && isFinite(opts.digits) && -1 !== initialValue.indexOf(opts.radixPoint)) {
                    var valueParts = initialValue.split(opts.radixPoint), decPart = valueParts[1].match(new RegExp("\\d*"))[0];
                    if (parseInt(opts.digits) < decPart.toString().length) {
                        var digitsFactor = Math.pow(10, parseInt(opts.digits));
                        initialValue = initialValue.replace(Inputmask.escapeRegex(opts.radixPoint), "."),
                        initialValue = Math.round(parseFloat(initialValue) * digitsFactor) / digitsFactor,
                        initialValue = initialValue.toString().replace(".", opts.radixPoint);
                    }
                }
                return initialValue.toString();
            },
            canClearPosition: function (maskset, position, lvp, strict, opts) {
                var positionInput = maskset.validPositions[position].input, canClear = positionInput !== opts.radixPoint || null !== maskset.validPositions[position].match.fn && opts.decimalProtect === !1 || isFinite(positionInput) || position === lvp || positionInput === opts.groupSeparator || positionInput === opts.negationSymbol.front || positionInput === opts.negationSymbol.back;
                if (canClear && isFinite(positionInput)) {
                    var matchRslt, radixPos = $.inArray(opts.radixPoint, maskset.buffer), radixInjection = !1;
                    if (void 0 === maskset.validPositions[radixPos] && (maskset.validPositions[radixPos] = {
                        input: opts.radixPoint
                    }, radixInjection = !0), !strict && maskset.buffer) {
                        matchRslt = maskset.buffer.join("").substr(0, position).match(opts.regex.integerNPart(opts));
                        var pos = position + 1, isNull = null == matchRslt || 0 === parseInt(matchRslt[0].replace(new RegExp(Inputmask.escapeRegex(opts.groupSeparator), "g"), ""));
                        if (isNull) for (; maskset.validPositions[pos] && (maskset.validPositions[pos].input === opts.groupSeparator || "0" === maskset.validPositions[pos].input) ;) delete maskset.validPositions[pos],
                        pos++;
                    }
                    var buffer = [];
                    for (var vp in maskset.validPositions) void 0 !== maskset.validPositions[vp].input && buffer.push(maskset.validPositions[vp].input);
                    if (radixInjection && delete maskset.validPositions[radixPos], radixPos > 0) {
                        var bufVal = buffer.join("");
                        if (matchRslt = bufVal.match(opts.regex.integerNPart(opts)), matchRslt && radixPos >= position) if (0 === matchRslt[0].indexOf("0")) canClear = matchRslt.index !== position || "0" === opts.placeholder; else {
                            var intPart = parseInt(matchRslt[0].replace(new RegExp(Inputmask.escapeRegex(opts.groupSeparator), "g"), "")), radixPart = parseInt(bufVal.split(opts.radixPoint)[1]);
                            10 > intPart && maskset.validPositions[position] && ("0" !== opts.placeholder || radixPart > 0) && (maskset.validPositions[position].input = "0",
                            maskset.p = opts.prefix.length + 1, canClear = !1);
                        }
                    }
                }
                return canClear;
            },
            onKeyDown: function (e, buffer, caretPos, opts) {
                var $input = $(this);
                if (e.ctrlKey) switch (e.keyCode) {
                    case Inputmask.keyCode.UP:
                        $input.val(parseFloat(this.inputmask.unmaskedvalue()) + parseInt(opts.step)), $input.triggerHandler("setvalue.inputmask");
                        break;

                    case Inputmask.keyCode.DOWN:
                        $input.val(parseFloat(this.inputmask.unmaskedvalue()) - parseInt(opts.step)), $input.triggerHandler("setvalue.inputmask");
                }
            }
        },
        currency: {
            prefix: "$ ",
            groupSeparator: ",",
            alias: "numeric",
            placeholder: "0",
            autoGroup: !0,
            digits: 2,
            digitsOptional: !1,
            clearMaskOnLostFocus: !1
        },
        decimal: {
            alias: "numeric"
        },
        integer: {
            alias: "numeric",
            digits: 0,
            radixPoint: ""
        },
        percentage: {
            alias: "numeric",
            digits: 2,
            radixPoint: ".",
            placeholder: "0",
            autoGroup: !1,
            min: 0,
            max: 100,
            suffix: " %",
            allowPlus: !1,
            allowMinus: !1
        }
    }), Inputmask;
}(jQuery, Inputmask), function ($, Inputmask) {
    return Inputmask.extendAliases({
        phone: {
            url: "phone-codes/phone-codes.js",
            countrycode: "",
            mask: function (opts) {
                opts.definitions["#"] = opts.definitions[9];
                var maskList = [];
                return $.ajax({
                    url: opts.url,
                    async: !1,
                    dataType: "json",
                    success: function (response) {
                        maskList = response;
                    },
                    error: function (xhr, ajaxOptions, thrownError) {
                        alert(thrownError + " - " + opts.url);
                    }
                }), maskList = maskList.sort(function (a, b) {
                    return (a.mask || a) < (b.mask || b) ? -1 : 1;
                });
            },
            keepStatic: !1,
            nojumps: !0,
            nojumpsThreshold: 1,
            onBeforeMask: function (value, opts) {
                var processedValue = value.replace(/^0/g, "");
                return (processedValue.indexOf(opts.countrycode) > 1 || -1 === processedValue.indexOf(opts.countrycode)) && (processedValue = "+" + opts.countrycode + processedValue),
                processedValue;
            }
        },
        phonebe: {
            alias: "phone",
            url: "phone-codes/phone-be.js",
            countrycode: "32",
            nojumpsThreshold: 4
        }
    }), Inputmask;
}(jQuery, Inputmask), function ($, Inputmask) {
    return Inputmask.extendAliases({
        Regex: {
            mask: "r",
            greedy: !1,
            repeat: "*",
            regex: null,
            regexTokens: null,
            tokenizer: /\[\^?]?(?:[^\\\]]+|\\[\S\s]?)*]?|\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9][0-9]*|x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4}|c[A-Za-z]|[\S\s]?)|\((?:\?[:=!]?)?|(?:[?*+]|\{[0-9]+(?:,[0-9]*)?\})\??|[^.?*+^${[()|\\]+|./g,
            quantifierFilter: /[0-9]+[^,]/,
            isComplete: function (buffer, opts) {
                return new RegExp(opts.regex).test(buffer.join(""));
            },
            definitions: {
                r: {
                    validator: function (chrs, maskset, pos, strict, opts) {
                        function RegexToken(isGroup, isQuantifier) {
                            this.matches = [], this.isGroup = isGroup || !1, this.isQuantifier = isQuantifier || !1,
                            this.quantifier = {
                                min: 1,
                                max: 1
                            }, this.repeaterPart = void 0;
                        }
                        function analyseRegex() {
                            var match, m, currentToken = new RegexToken(), opengroups = [];
                            for (opts.regexTokens = []; match = opts.tokenizer.exec(opts.regex) ;) switch (m = match[0],
                            m.charAt(0)) {
                                case "(":
                                    opengroups.push(new RegexToken(!0));
                                    break;

                                case ")":
                                    groupToken = opengroups.pop(), opengroups.length > 0 ? opengroups[opengroups.length - 1].matches.push(groupToken) : currentToken.matches.push(groupToken);
                                    break;

                                case "{":
                                case "+":
                                case "*":
                                    var quantifierToken = new RegexToken(!1, !0);
                                    m = m.replace(/[{}]/g, "");
                                    var mq = m.split(","), mq0 = isNaN(mq[0]) ? mq[0] : parseInt(mq[0]), mq1 = 1 === mq.length ? mq0 : isNaN(mq[1]) ? mq[1] : parseInt(mq[1]);
                                    if (quantifierToken.quantifier = {
                                        min: mq0,
                                        max: mq1
                                    }, opengroups.length > 0) {
                                        var matches = opengroups[opengroups.length - 1].matches;
                                        match = matches.pop(), match.isGroup || (groupToken = new RegexToken(!0), groupToken.matches.push(match),
                                        match = groupToken), matches.push(match), matches.push(quantifierToken);
                                    } else match = currentToken.matches.pop(), match.isGroup || (groupToken = new RegexToken(!0),
                                    groupToken.matches.push(match), match = groupToken), currentToken.matches.push(match),
                                    currentToken.matches.push(quantifierToken);
                                    break;

                                default:
                                    opengroups.length > 0 ? opengroups[opengroups.length - 1].matches.push(m) : currentToken.matches.push(m);
                            }
                            currentToken.matches.length > 0 && opts.regexTokens.push(currentToken);
                        }
                        function validateRegexToken(token, fromGroup) {
                            var isvalid = !1;
                            fromGroup && (regexPart += "(", openGroupCount++);
                            for (var mndx = 0; mndx < token.matches.length; mndx++) {
                                var matchToken = token.matches[mndx];
                                if (matchToken.isGroup === !0) isvalid = validateRegexToken(matchToken, !0); else if (matchToken.isQuantifier === !0) {
                                    var crrntndx = $.inArray(matchToken, token.matches), matchGroup = token.matches[crrntndx - 1], regexPartBak = regexPart;
                                    if (isNaN(matchToken.quantifier.max)) {
                                        for (; matchToken.repeaterPart && matchToken.repeaterPart !== regexPart && matchToken.repeaterPart.length > regexPart.length && !(isvalid = validateRegexToken(matchGroup, !0)) ;);
                                        isvalid = isvalid || validateRegexToken(matchGroup, !0), isvalid && (matchToken.repeaterPart = regexPart),
                                        regexPart = regexPartBak + matchToken.quantifier.max;
                                    } else {
                                        for (var i = 0, qm = matchToken.quantifier.max - 1; qm > i && !(isvalid = validateRegexToken(matchGroup, !0)) ; i++);
                                        regexPart = regexPartBak + "{" + matchToken.quantifier.min + "," + matchToken.quantifier.max + "}";
                                    }
                                } else if (void 0 !== matchToken.matches) for (var k = 0; k < matchToken.length && !(isvalid = validateRegexToken(matchToken[k], fromGroup)) ; k++); else {
                                    var testExp;
                                    if ("[" == matchToken.charAt(0)) {
                                        testExp = regexPart, testExp += matchToken;
                                        for (var j = 0; openGroupCount > j; j++) testExp += ")";
                                        var exp = new RegExp("^(" + testExp + ")$");
                                        isvalid = exp.test(bufferStr);
                                    } else for (var l = 0, tl = matchToken.length; tl > l; l++) if ("\\" !== matchToken.charAt(l)) {
                                        testExp = regexPart, testExp += matchToken.substr(0, l + 1), testExp = testExp.replace(/\|$/, "");
                                        for (var j = 0; openGroupCount > j; j++) testExp += ")";
                                        var exp = new RegExp("^(" + testExp + ")$");
                                        if (isvalid = exp.test(bufferStr)) break;
                                    }
                                    regexPart += matchToken;
                                }
                                if (isvalid) break;
                            }
                            return fromGroup && (regexPart += ")", openGroupCount--), isvalid;
                        }
                        var groupToken, cbuffer = maskset.buffer.slice(), regexPart = "", isValid = !1, openGroupCount = 0;
                        null === opts.regexTokens && analyseRegex(), cbuffer.splice(pos, 0, chrs);
                        for (var bufferStr = cbuffer.join(""), i = 0; i < opts.regexTokens.length; i++) {
                            var regexToken = opts.regexTokens[i];
                            if (isValid = validateRegexToken(regexToken, regexToken.isGroup)) break;
                        }
                        return isValid;
                    },
                    cardinality: 1
                }
            }
        }
    }), Inputmask;
}(jQuery, Inputmask);;
/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * Version: 1.3.1
 *
 */
(function(f){jQuery.fn.extend({slimScroll:function(h){var a=f.extend({width:"auto",height:"250px",size:"7px",color:"#000",position:"right",distance:"1px",start:"top",opacity:0.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:0.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:"7px",railBorderRadius:"7px"},h);this.each(function(){function r(d){if(s){d=d||
window.event;var c=0;d.wheelDelta&&(c=-d.wheelDelta/120);d.detail&&(c=d.detail/3);f(d.target||d.srcTarget||d.srcElement).closest("."+a.wrapperClass).is(b.parent())&&m(c,!0);d.preventDefault&&!k&&d.preventDefault();k||(d.returnValue=!1)}}function m(d,f,h){k=!1;var e=d,g=b.outerHeight()-c.outerHeight();f&&(e=parseInt(c.css("top"))+d*parseInt(a.wheelStep)/100*c.outerHeight(),e=Math.min(Math.max(e,0),g),e=0<d?Math.ceil(e):Math.floor(e),c.css({top:e+"px"}));l=parseInt(c.css("top"))/(b.outerHeight()-c.outerHeight());
e=l*(b[0].scrollHeight-b.outerHeight());h&&(e=d,d=e/b[0].scrollHeight*b.outerHeight(),d=Math.min(Math.max(d,0),g),c.css({top:d+"px"}));b.scrollTop(e);b.trigger("slimscrolling",~~e);v();p()}function C(){window.addEventListener?(this.addEventListener("DOMMouseScroll",r,!1),this.addEventListener("mousewheel",r,!1),this.addEventListener("MozMousePixelScroll",r,!1)):document.attachEvent("onmousewheel",r)}function w(){u=Math.max(b.outerHeight()/b[0].scrollHeight*b.outerHeight(),D);c.css({height:u+"px"});
var a=u==b.outerHeight()?"none":"block";c.css({display:a})}function v(){w();clearTimeout(A);l==~~l?(k=a.allowPageScroll,B!=l&&b.trigger("slimscroll",0==~~l?"top":"bottom")):k=!1;B=l;u>=b.outerHeight()?k=!0:(c.stop(!0,!0).fadeIn("fast"),a.railVisible&&g.stop(!0,!0).fadeIn("fast"))}function p(){a.alwaysVisible||(A=setTimeout(function(){a.disableFadeOut&&s||(x||y)||(c.fadeOut("slow"),g.fadeOut("slow"))},1E3))}var s,x,y,A,z,u,l,B,D=30,k=!1,b=f(this);if(b.parent().hasClass(a.wrapperClass)){var n=b.scrollTop(),
c=b.parent().find("."+a.barClass),g=b.parent().find("."+a.railClass);w();if(f.isPlainObject(h)){if("height"in h&&"auto"==h.height){b.parent().css("height","auto");b.css("height","auto");var q=b.parent().parent().height();b.parent().css("height",q);b.css("height",q)}if("scrollTo"in h)n=parseInt(a.scrollTo);else if("scrollBy"in h)n+=parseInt(a.scrollBy);else if("destroy"in h){c.remove();g.remove();b.unwrap();return}m(n,!1,!0)}}else{a.height="auto"==a.height?b.parent().height():a.height;n=f("<div></div>").addClass(a.wrapperClass).css({position:"relative",
overflow:"hidden",width:a.width,height:a.height});b.css({overflow:"hidden",width:a.width,height:a.height});var g=f("<div></div>").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&&a.railVisible?"block":"none","border-radius":a.railBorderRadius,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=f("<div></div>").addClass(a.barClass).css({background:a.color,width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible?
"block":"none","border-radius":a.borderRadius,BorderRadius:a.borderRadius,MozBorderRadius:a.borderRadius,WebkitBorderRadius:a.borderRadius,zIndex:99}),q="right"==a.position?{right:a.distance}:{left:a.distance};g.css(q);c.css(q);b.wrap(n);b.parent().append(c);b.parent().append(g);a.railDraggable&&c.bind("mousedown",function(a){var b=f(document);y=!0;t=parseFloat(c.css("top"));pageY=a.pageY;b.bind("mousemove.slimscroll",function(a){currTop=t+a.pageY-pageY;c.css("top",currTop);m(0,c.position().top,!1)});
b.bind("mouseup.slimscroll",function(a){y=!1;p();b.unbind(".slimscroll")});return!1}).bind("selectstart.slimscroll",function(a){a.stopPropagation();a.preventDefault();return!1});g.hover(function(){v()},function(){p()});c.hover(function(){x=!0},function(){x=!1});b.hover(function(){s=!0;v();p()},function(){s=!1;p()});b.bind("touchstart",function(a,b){a.originalEvent.touches.length&&(z=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){k||b.originalEvent.preventDefault();b.originalEvent.touches.length&&
(m((z-b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0),z=b.originalEvent.touches[0].pageY)});w();"bottom"===a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),m(0,!0)):"top"!==a.start&&(m(f(a.start).position().top,null,!0),a.alwaysVisible||c.hide());C()}});return this}});jQuery.fn.extend({slimscroll:jQuery.fn.slimScroll})})(jQuery);;
/**
 * Listbox.js is a simple jQuery plugin that provides a more powerful
 * alternative to the standard `<select>` tag.
 *
 * The main problem of <select> tag is that last one isn't flexible for
 * customization with CSS. Listbox.js solves this problem. This component
 * runs on top of <select> tag and creates an alternative to the last one
 * based on <div> tags. It opens up great possibilities for customization.
 *
 * @copyright   (c) 2012, Igor Kalnitsky <igor@kalnitsky.org>
 * @version     0.3.0-dev
 * @license     BSD
 */

(function ($) {
    'use strict';


    // CSS classes used by Listbox.js
    var MAIN_CLASS      = 'lbjs';
    var LIST_CLASS      = 'lbjs-list';
    var LIST_ITEM_CLASS = 'lbjs-item';
    var SEARCHBAR_CLASS = 'lbjs-searchbar';



    /**
     * Inherit the prototype methods from one constructor into another.
     * The prototype of `constructor` will be set to a new object created
     * from `superConstructor`.
     *
     * As an additional convenience, `superConstructor` will be accessible
     * through the `constructor.super_` property.
     */
    function inherits(constructor, superConstructor) {
        // Custom catch
        try {
            constructor.prototype = Object.create(superConstructor.prototype);
            constructor.prototype.constructor = constructor;
            constructor.prototype.super_ = superConstructor;
        } catch (ex) {

        }
    }



    /**
     * Create an instance of Listbox. The constructor makes div-based
     * listbox alternative for the sandard's `<select>` tag, hide parent
     * element and place the alternative on the parent place.
     *
     * @constructor
     * @this {Listbox}
     * @param {object} domelement DOM element to be converted to the Listbox
     * @param {object} options an object with Listbox settings
     */
    function Listbox(domelement, options) {
        var settings = $.extend({
            'class':      null,
            'searchbar':  false
        }, options);

        this._parent   = domelement;
        this._settings = settings;

        this._createListbox();                // create a fake listbox
        this._parent.css('display', 'none');  // hide a parent element
    }



    /**
     * Creates a `div`-based listbox, which includes such things as
     * container, listbox itself and searchbar as an optional element.
     *
     * @private
     * @this {Listbox}
     */
    Listbox.prototype._createListbox = function () {
        this._listbox = $('<div>')
            .addClass(MAIN_CLASS)
            .addClass(this._settings['class'])
            .insertAfter(this._parent)
        ;

        if (this._settings.searchbar)
            this._createSearchbar();
        this._createList();
    };

    /**
     * Creates a Listbox's searchbar.
     *
     * @private
     * @this {Listbox}
     * @TODO: critical to rewrite this piece of shit
     */
    Listbox.prototype._createSearchbar = function () {
        // searchbar wrapper is needed for properly stretch
        // the seacrhbar over the listbox width
        var searchbarWrapper = $('<div>')
            .addClass(SEARCHBAR_CLASS + '-wrapper')
            .appendTo(this._listbox);

        var searchbar = $('<input>')
            .addClass(SEARCHBAR_CLASS)
            .appendTo(searchbarWrapper)
            .attr('placeholder', 'search...');

        // set filter handler
        var self = this;
        searchbar.keyup(function () {
            var searchQuery = $(this).val().toLowerCase();

            if (searchQuery !== '') {
                // hide list items which are not matched search query
                self._list.children().each(function (index) {
                    var text = $(this).text().toLowerCase();

                    if (text.search('^' + searchQuery) != -1) {
                        $(this).css('display', 'block');
                    } else {
                        $(this).css('display', 'none');
                    }
                });
            } else {
                // make visible all list items
                self._list.children().each(function () {
                    $(this).css('display', 'block');
                });
            }

            // @hack: call special handler which is used only for SingleSelectListbox
            //        to prevent situation when none of items are selected
            if (self.onFilterChange) {
                self.onFilterChange();
            }
        });

        // save for using in _resizeListToListbox()
        this._searchbarWrapper = searchbarWrapper;
    };


    /**
     * Creates a listbox itself.
     *
     * @private
     * @this {Listbox}
     */
    Listbox.prototype._createList = function () {
        // create container
        this._list = $('<div>')
            .addClass(LIST_CLASS)
            .appendTo(this._listbox);

        this._resizeListToListbox();

        // create items
        var self = this;
        this._parent.children().each(function () {
            self.addItem($(this));
        });
    };




    /**
     * Add item to the listbox.
     *
     * @this {Listbox}
     * @param {object} parentItem DOM element of the parent options
     */
    Listbox.prototype.addItem = function (parentItem) {
        var self = this;
        var item = $('<div>')
            .addClass(LIST_ITEM_CLASS)
            .appendTo(this._list)
            .text(parentItem.text())
            .click(function () {
                self.onItemClick($(this));
            });

        if (parentItem.attr('disabled'))
            item.attr('disabled', '');

        if (parentItem.attr('selected'))
            item.attr('selected', '');
    };




    /**
     * Remove item from the listbox.
     *
     * @this {Listbox}
     * @param {object} parentItem DOM element of the parent options
     */
    Listbox.prototype.removeItem = function (parentItem) {
        // @todo: implement
    };




    /**
     * Resize list to lisbox. It's a small hack since I can't
     * do it with CSS.
     *
     * @private
     */
    Listbox.prototype._resizeListToListbox = function () {
        var listHeight = this._listbox.height();

        if (this._settings.searchbar)
            listHeight -= this._searchbarWrapper.outerHeight(true);

        this._list.height(listHeight);
    };




    /**
     * Create an instance of SingleSelectListbox.
     *
     * Inherit a {Listbox} class.
     *
     * @constructor
     * @this {SingleSelectListbox}
     * @param {object} domelement DOM element to be converted to the Listbox
     * @param {object} options an object with Listbox settings
     */
    function SingleSelectListbox(domelement, options) {
        this.super_.call(this, domelement, options);

        // select first item if none selected
        if (!this._selected)
            this.onItemClick(this._list.children().first());
    }
    inherits(SingleSelectListbox, Listbox);


    /**
     * Reset all items and select a given one.
     *
     * @this {SingleSelectListbox}
     * @param {object} item a DOM object
     */
    SingleSelectListbox.prototype.onItemClick = function (item) {
        if (this._parent.attr('disabled') || this._parent.attr('readonly')) return;

        // select a fake item
        if (this._selected)
            this._selected.removeAttr('selected');
        this._selected = item.attr('selected', '');

        // select a real item
        var itemToSelect = $(this._parent.children().get(item.index()));
        this._parent.val(itemToSelect.val());

        this._parent.trigger('change');
    };


    /**
     * Select first visible item if none selected.
     *
     * @this {SingleSelectListbox}
     */
    SingleSelectListbox.prototype.onFilterChange = function () {
        if (!this._selected || !this._selected.is(':visible'))
            this.onItemClick(this._list.children(':visible').first());
    };




    /**
     * Create an instance of MultiSelectListbox.
     *
     * Inherit a {Listbox} class.
     *
     * @constructor
     * @this {MultiSelectListbox}
     * @param {object} domelement DOM element to be converted to the Listbox
     * @param {object} options an object with Listbox settings
     */
    function MultiSelectListbox(domelement, options) {
        this.super_.call(this, domelement, options);
    }
    inherits(MultiSelectListbox, Listbox);




    /**
     * Toggle item status.
     *
     * @this {MultiSelectListbox}
     * @param {object} item a DOM object
     */
    MultiSelectListbox.prototype.onItemClick = function (item) {
        if (this._parent.attr('disabled') || this._parent.attr('readonly')) return;

        var parentItem = $(this._parent.children().get(item.index()));
        var parentValue = this._parent.val();

        if (item.attr('selected')) {
            item.removeAttr('selected');

            var removeIndex = parentValue.indexOf(parentItem.val());
            parentValue.splice(removeIndex, 1);
        } else {
            item.attr('selected', '');

            if (!parentValue)
                parentValue = [];
            parentValue.push(parentItem.val());
        }

        this._parent.val(parentValue);
        this._parent.trigger('change');
    };




    /**
     * jQuery plugin definition. Please note, that jQuery's `each()` method
     * returns `false` to stop iteration; otherwise it should return `true`.
     *
     * @param {object} options an object with Listbox settings
     */
    $.fn.listbox = function (options) {
        return this.each(function () {
            if ($(this).attr('multiple'))
                return !!new MultiSelectListbox($(this), options);
            return !!new SingleSelectListbox($(this), options);
        });
    };
})(jQuery);
;

function setupAccordions() {
    setupAccordion($('.accordion'));
}


function setupAccordion($accordion) {
    $accordion.each(function() {
        var $toggle = $accordion.find('.toggle .collapse, .toggle .expand');
        $toggle.click(handleAccordionToggle);
    });
}


function handleAccordionToggle() {
    toggleAccordion($(this).closest('.accordion'));
}


function toggleAccordion($accordion) {
    var $toggle = $accordion.find('.toggle .collapse, .toggle .expand');
    var $content = $accordion.find('.content');

    if ($toggle.hasClass('expand')) {
        $content.slideDown(function() {
            $accordion.removeClass('closed').addClass('open');
            $toggle.removeClass('expand').addClass('collapse');
            calculateStickies();
        });
    } else {
        $content.slideUp(function() {
            $accordion.removeClass('open').addClass('closed');
            $toggle.removeClass('collapse').addClass('expand');
            calculateStickies();
        });
    }
};
// ---- Validation and Delete ---- //

/**@description Displays a popup asking the user to confirm the delete.
 * @param {string} [title] Optional. Heading text.
 * @param {string} message Main message to inform the user what is happening.
 * @param {function} callback Function called on confirmation.
 * @param {string} [subTitle] Optional. Text displayed below the header.
 */
function showDeletePopup(title, subTitle, message, callback, postback) {
    showConfirmPopup(message, callback, postback, null, null, title, subTitle);
}


/**@description Displays a popup asking the user to confirm a validatated action (e.g. deletes).
 * @param {string} [title] the title for the validation error message.
 * @param {string} [url] the url of the validation action.
 * @param {function} callback Function called on passing - triggers a confirmation usually.
 * @param {object} [postback] used by the callback to determine which item to action.
 */
function validateAction(title, url, callback, postback) {
    showLoadingAnimation();

    $.ajax({
        type: 'POST',
        url: url
    })
    .done(function (result) {
        if (result.IsSuccess) {
            hideLoadingAnimation(false);
            if (callback) {
                callback(postback, result);
            }
        } else {
            hideLoadingAnimation(false);
            showLockedMessage(title, result);
        }
    })
   .fail(handleAjaxError);
}


/**@description Wrapper to cleanly handle a delete action
 * @param {string} [title] the title for the confirmation message.
 * @param {string} [message] the text of the confirmation message.
 * @param {string} [url] the url of the delete action.
 * @param {function} callback Function called on passing - triggers a cleanup function.
 * @param {object} [postback] used by the callback to determine which item to action.
 * @param {object} [validationReponse] General warnings from a validation. Pass the ValidationReponse.
 */
function confirmThenDelete(title, message, url, callback, postback, validationResponse) {
    // If the validation response exists THEN add the warning text to the popup.
    if (validationResponse) {
       message = message.concat(convertWarningsToPopupText(validationResponse));
    }

    showDeletePopup(title, null, message, function () {
        showLoadingAnimation();

        $.ajax({
            type: 'POST',
            url: url
        })
        .done(function (result) {
            // Will need to confirm this line does not interfare elsewhere.
            hideLoadingAnimation(true);

            if (result.IsSuccess) {
                if (callback) {
                    callback(postback);
                }
            } else {
                hideLoadingAnimation();
                showErrorMessage(result.Validation.Errors[0].Value);
            }
        })
        .fail(handleAjaxError);
    });
}



/** @description Converts the warnings from a ValidationResult to a HTML element that can be added to a popup.
 * @param {string} validationResult The ValidatioNResult from the server.
 */
function convertWarningsToPopupText(validationResult) {
    var html = '';

    if (validationResult) {
        if (validationResult.HasConfirmations) {
            html = '<ul class="container">';

            for (var i = 0; i < validationResult.Validation.Warnings.length; i++) {
                html = html + '<li>' + validationResult.Validation.Warnings[i].Value + '</li>';
            }

            html = html + '</ul>';
        }
    }

    return html
}
;

// TODO: Review and comment.

function setupDynamicFields() {
    setupDynamicField($('input.dynamic-field').not('.k-input'));
}


function setupDynamicField($dynamicFields) {
    $dynamicFields.each(function () {
        toggleDynamicField($(this));

        $(this).change(function () {
            toggleDynamicField($(this));
        });
    });
}


function toggleDynamicField($dynamicField) {
    //var fieldId = $dynamicField.attr('data-field-id');
    var fieldId = $dynamicField.attr('id');
    var $input = $('#' + fieldId);
    var $buttons = $('.field-buttons[data-field-id=' + fieldId + '] button');

    if ($input.val() && $input.val() !== EMPTY_GUID) {
        $buttons.filter('.set').show();
        $buttons.filter('.unset').hide();
    } else {
        $buttons.filter('.unset').show();
        $buttons.filter('.set').hide();
    }
}



function setupDynamicDropDowns() {
    setupDynamicDropDown($('.k-dropdown.dynamic-field'));
    setupDynamicComboBox($('.k-combobox.dynamic-field'));
}


function setupDynamicDropDown($dynamicDropDowns) {
    $dynamicDropDowns.each(function () {
        var $dropDown = $(this);
        var $dynamicField = $dropDown.find('input.dynamic-field').not('.k-input');
        var $dropDownWrap = $dropDown.find('span.k-dropdown-wrap');
        var fieldId = $dynamicField.attr('data-field-id');
        var $dropDownButton = $('.field-buttons[data-field-id=' + fieldId + '] button.drop-down-button');
        var kendoDropDown = $dynamicField.data().kendoDropDownList;

        $dropDownButton.unbind(); // remove previous bind events 

        kendoDropDown.bind("open", function () { $dropDownButton.addClass('open'); });
        kendoDropDown.bind("close", function () { $dropDownButton.removeClass('open'); });

        $dropDown.on('focus', function () { $dropDownButton.addClass('focus'); });
        $dropDown.on('blur', function () { $dropDownButton.removeClass('focus'); });

        $dropDownWrap.hover(function () {
            $dropDownButton.addClass('hover');
        }, function () {
            $dropDownButton.removeClass('hover');
        });

        $dropDownButton.hover(function () {
            $dropDownWrap.mouseover();
        }, function () {
            $dropDownWrap.mouseout();
        });

        $dropDownButton.focus(function () { $dropDown.focus(); });
        $dropDownButton.blur(function () { $dropDown.blur(); });
        $dropDownButton.click(function () { $dropDownWrap.click(); });
    });
}


function setupDynamicComboBox($dynamicComboBoxes) {
    $dynamicComboBoxes.each(function () {
        var $comboBox = $(this);
        var $dynamicField = $comboBox.find('input.dynamic-field').not('.k-input');
        var $comboSelect = $comboBox.find('span.k-select');
        var fieldId = $dynamicField.attr('id');
        var $dropDownButton = $('.field-buttons[data-field-id=' + fieldId + '] button.drop-down-button');
        var kendoDropDown = $dynamicField.data().kendoComboBox;

        $dropDownButton.addClass('combo-box');
        kendoDropDown.bind("open", function () { $dropDownButton.addClass('open'); });
        kendoDropDown.bind("close", function () { $dropDownButton.removeClass('open'); });

        $dropDownButton.click(function () { $comboSelect.click(); });
    });
};

function setupEditableCards() {
    setupEditableCard($('.editable-card'));
}


function setupEditableCard($card) {
    $card.each(function () {
        var $card = $(this);
        var $display = $card.find('.display.card');
        var $edit = $card.find('.edit.card');

        // Ensure display is shown first
        $edit.hide();
        $display.show();

        // Setup events
        $card.find('.card-toggle').click(function() { toggleCard($card); });

        // Check for errors
        if ($card.find('.field-validation-error, .validation-summary-errors').length) {
            // Switch to edit mode if there are errors to display.
            $display.find('.card-toggle').click();

            // If a validation error occurs THEN reload the page when the user clicks cancel.
            $edit.find('.card-toggle').unbind('click').click(function(e) {
                showLoadingAnimation();
                window.location = window.location.href;
            });
        }
    });
}



// Toggles the given Editable Card between display and edit modes.
function toggleCard($card) {
    $display = $card.find('.display.card');
    $edit = $card.find('.edit.card');

    if ($display.is(':visible')) {
        $display.hide();
        $edit.show();
    } else {
        $display.show();
        $edit.hide();
    }
};

/**@description Initial page setup for automatic tooltips on ellipses.
 */
function setupEllipses() {
    setupEllipsis($('.ellipsis, .ellipses'));
}


/**@description Creates automatic tooltips on ellipses.
 */
function setupEllipsis($ellipsis) {
    $ellipsis.each(function() {
        var width = $(this).width();
        var leftPadding = $(this).css('padding-left').replace("px", "");

        // If class is 'ellipses' (plural) then it is the children that need checking.
        if ($(this).hasClass('ellipses')) {
            // Measure children against parent
            $(this).children().each(function() {
                var right = $(this).position().left - leftPadding + $(this).width();

                if (right > width) {
                    addAutoToolTip($(this));
                } else {
                    removeAutoToolTip($(this));
                }
            });

            return;
        }

        // Single ellipsis.
        var tolerance = 0; // TODO: Review if tolerance is necessary.

        if (getNaturalWidth($(this)) > ($(this).width() + tolerance)) {
            addAutoToolTip($(this));
        } else {
            removeAutoToolTip($(this));
        }
    });

}


/**@description Sets the tooltip of an element based on its content. Only triggered if there isn't already a tooltip.
 */
function addAutoToolTip($item) {
    if (!$item.attr('title') || $item.attr('data-auto-tooltip')) {
        $item.attr('title', $item.text());
        $item.attr('data-auto-tooltip', true);
    }
}


/**@description Reverses result of addAutoToolTip.
 */
function removeAutoToolTip($item) {
    if ($item.attr('data-auto-tooltip')) {
        $item.attr('title', null);
        $item.attr('data-auto-tooltip', false);
    }
}


/**@description Attempts to measure the natural width of an element as if it was unrestricted.
 */
function getNaturalWidth($item) {
    var $dummy = $item.clone();

    // Attempt to style the element so that retains its natural width but is not visible to the user.
    $dummy.css({ visibility: 'hidden', position: 'absolute', top: 0, left: 0, width: 'auto', 'max-width': '' });

    // Needs to be positioned inside the parent to ensure font size remains intact.
    $item.parent().append($dummy);

    // Measure
    var width = $dummy.width();
    $dummy.remove();

    return width;
};

/**@description Initial page setup for automatic tooltips on ellipses.
 */
function setupEllipses() {
    setupEllipsis($('.ellipsis, .ellipses'));
}


/**@description Creates automatic tooltips on ellipses.
 */
function setupEllipsis($ellipsis) {
    $ellipsis.each(function() {
        var width = $(this).width();
        var leftPadding = $(this).css('padding-left').replace("px", "");

        // If class is 'ellipses' (plural) then it is the children that need checking.
        if ($(this).hasClass('ellipses')) {
            $(this).children().each(function() {
                if ($(this).css('display') == 'inline') {
                    // Measure children against parent
                    var right = $(this).position().left - leftPadding + $(this).width();

                    if (right > width) {
                        addAutoToolTip($(this));
                    } else {
                        removeAutoToolTip($(this));
                    }
                } else {
                    // Measure element's text against itself
                    setupAutoToolTip($(this));
                    $(this).addClass('ellipsis');
                }
            });
        } else {
            // Single ellipsis - Measure element's text against itself
            setupAutoToolTip($(this));
        }
    });
}


/*@description Determines if the given element's text is overflowing and applies a tooltip.
 */
function setupAutoToolTip($item) {
    var tolerance = 0; // Note: Alter if tolerance is necessary.

    if (getNaturalWidth($item) > ($item.width() + tolerance)) {
        addAutoToolTip($item);
        return true;
    } else {
        removeAutoToolTip($item);
        return false;
    }
}



/**@description Sets the tooltip of an element based on its content. Only triggered if there isn't already a tooltip.
 */
function addAutoToolTip($item) {
    if (!$item.attr('title') || $item.attr('data-auto-tooltip')) {
        $item.attr('title', $item.text());
        $item.attr('data-auto-tooltip', true);
    }
}


/**@description Reverses result of addAutoToolTip.
 */
function removeAutoToolTip($item) {
    if ($item.attr('data-auto-tooltip')) {
        $item.attr('title', null);
        $item.attr('data-auto-tooltip', false);
    }
}


/**@description Attempts to measure the natural width of an element as if it was unrestricted.
 */
function getNaturalWidth($item) {
    var $dummy = $item.clone();

    // Attempt to style the element so that retains its natural width but is not visible to the user.
    $dummy.css({ visibility: 'hidden', position: 'absolute', top: 0, left: 0, width: 'auto', 'max-width': '' });

    // Needs to be positioned inside the parent to ensure font size remains intact.
    $item.parent().append($dummy);

    // Measure
    var width = $dummy.width();
    $dummy.remove();

    return width;
};
var _formChanged = false;

/**@description Performs setup logic on all forms.
 */
function setupForms() {
    setupForm($('form'));

    // Confirm discarding of unsaved changes
    $(window).bind('beforeunload', function () {
        if (_formChanged) {
            return LNG_UNSAVED_CHANGES;
        }
    });
}

/**@description Performs setup logic on specific forms.
 */
function setupForm($form) {
    $form.submit(function (e) {
        if ($(this).data('submitted')) {
            e.preventDefault();
            return;
        }

        // TODO: Needs to be written to standard and be selective on what inputs it applies to.
        setupMaskedTextboxesBeforeSubmit();

        // Force validation
        $(this).validate();

        // Valid?
        if ($(this).valid() && $(this).attr('action')) {
            _formChanged = false;

            // Loading animation on submit button
            $(this).find('button[type="submit"][data-clicked=clicked]').addClass("clicked");
            $(this).data('submitted', true);
        } else {
            // Switch to tab with error (if any)
            var $tabStrips = $(".k-tabstrip");
            var errorTab = findErrorTab($tabStrips);

            if (errorTab) {
                selectTab($tabStrips, errorTab);
            }
        }
    });

    // Find all submission buttons
    $form.find('button[type="submit"]').click(function () {
        // Flag latest click as the as clicked button, remove others.
        $(this).parents("form").find("input[type=submit]").attr("data-clicked", '');
        $(this).attr("data-clicked", "clicked");
    });
}


/** @description Checks to see if there are unsaved changes on a page
 *  @returns {Bool} A value indicating whether a user wants to leave the page or not. 
 */
function checkUnsavedChanges() {
    // Check to see if the form has changed.
    if (_formChanged) {
        // Ask the user if they want to stay on the page.
        var leavePage = confirm(LNG_UNSAVED_CHANGES);

        // If the user wants to leave the page THEN clear the formChanged variable so the message won't reappear on ajax pages.
        if (leavePage) {
            _formChanged = false;
        }

        // Returns the users decision.
        return leavePage;
    }
    else {
        // Leave the page if the form hasn't been changed.
        return true;
    }
}



// #region --- Validation ---

/**@description Performs validation setup logic on all forms.
 */
function setupValidation() {
    setupValidator($('form'));

    // Date validation fix
    $.validator.methods.date = function (value, element) {
        return this.optional(element) || true;
    };
}

/**@description Performs validation setup logic on specific forms.
 */
function setupValidator($form) {
    $form.each(function () {
        var validator = $(this).data().validator;

        // Hidden fields are validated except those that are only required when visible.
        validator.settings.ignore = "[data-val-required-visible]:hidden";

        // only validate on form submit
        validator.settings.onkeyup = false;
        validator.settings.onfocusout = false;
    });

    setupKendoValidator($form.find('.k-widget'))
}


/**@description Reconfigures validation on all forms.
 */
function resetValidation() {
    resetValidator($('form'));
}

/**@description Reconfigures validation on specific forms.
 */
function resetValidator($form) {
    $form.each(function () {
        // Remove current validation data
        $.data(this, 'validator', false);

        $(this).removeData('validator');
        $(this).removeData('unobtrusiveValidation');

        // Re-parse validation attributes
        $.validator.unobtrusive.parse(this);
    });

    setupValidator($form);
}



/**@description Performs validation setup logic on all inputs.
 */
function setupKendoValidation() {
    setupKendoValidator($('.k-widget'));
}


/**@description Performs validation setup logic on specific kendo inputs.
 */
function setupKendoValidator($input) {
    // There's a known validation issue with Kendo:
    // http://docs.telerik.com/aspnet-mvc/troubleshoot/troubleshooting-validation#widgets-are-hidden-after-postbacks-when-using-jquery-validation
    $input.each(function () {
        $(this).removeClass("input-validation-error");;
    });
}


/**@description Displays the errors from ValidationResult object JSON.
 */
function addValidationResultMessages(validationResult, $summaryContainer) {
    var errors = validationResult.Errors;

    for (var i = 0; i < errors.length; i++) {
        if (!addValidationMessage(errors[i].Key, errors[i].Value)) {
            addValidationSummaryMessage(errors[i].Value, null, $summaryContainer);
        }
    }
}


/**@description Finds the applicable validation container and sets the message. Returns a bool indicating success.
 */
function addValidationMessage(fieldName, message) {
    var $message = $('.field-validation-valid, .field-validation-error').filter('[data-valmsg-for="' + fieldName + '"]');

    if ($message.length) {
        if ($message.is('.field-validation-valid')) {
            $message.removeClass('field-validation-valid');
            $message.addClass('field-validation-error');
        }

        $message.text(message);
        return true;
    } else {
        return false;
    }
}


/**@description Appends a validation message to the validation summary.
 */
function addValidationSummaryMessage(message, itemClass, $container) {
    var $summary = $container.find('.validation-summary-errors');

    // Summary already present?
    if (!$summary.length) {
        $summary = $('<div class="validation-summary-errors"></div>');
        $container.append($summary);
    }
    
    // List already present?
    var $list = $summary.find('ul');
    
    if (!$list.length) {
        $list = $('<ul></ul>');
        $summary.append($list);
    }

    $list.append('<li class="' + itemClass + '">' + message + '</li>');
}


/**@description Finds and removes the validation message for the given field.
 */
function removeFieldValidationMessage(fieldName) {
    var $message = $('.field-validation-error').filter('[data-valmsg-for="' + fieldName + '"]');

    if ($message.length) {
        $message.removeClass('field-validation-error');
        $message.addClass('field-validation-valid');
        $message.text('');
        return true;
    } else {
        return false;
    }
}


/**@description Finds and removes all the validation message in the given container.
 */
function removeFieldValidationMessages($container) {
    var $message = $container.find('.field-validation-error');

    if ($message.length) {
        $message.removeClass('field-validation-error');
        $message.addClass('field-validation-valid');
        $message.text('');
        return true;
    } else {
        return false;
    }
}

// #endregion



// #region --- Inputs --- //

/**@description Performs setup logic on all inputs.
 */
function setupInputs() {
    setupInput($('input, select, textarea'));
}

/**@description Performs setup logic on specific inputs.
 */
function setupInput($input) {
    $input.change(function () {
        // Fields to ignore
        if (!$(this).closest('form').hasClass('js-ignore') && // Ignored specific forms
            !$(this).hasClass('row-selection') && // Grid selection
            !$(this).hasClass('js-ignore') && // Specific fields
            !($(this).hasClass('zeroed-to-null') && !$(this).val()) && // Numeric Fields zeros converted to null.
            !($(this).closest('.k-filtercell').length) && // ignore filtering
            !$(this).closest('.js.popup').length) { // Popups

            _formChanged = true;
        }

    });

    $input.each(function () {
        // Prefix asterix to require input labels.
        if ($(this).attr('data-val-required')) {
            var $label = $('label[for="' + $(this).attr('id') + '"]');
            $label.html(' <span class="required">* </span>' + $label.html());
        }

        // Kendo Controls
        var $kendo = $(this).closest('.k-widget');
        if ($kendo.length) {
            // Drop downs
            if ($kendo.hasClass('k-dropdown')) {
                setupDropDown($(this));
            }

            // Comboboxes
            if ($kendo.hasClass('k-combobox')) {
                setupComboBox($(this));
            }

            // Custom autocomplete comboboxes
            if ($kendo.hasClass('autocomplete')) {
                setupAutoCompleteCombo($(this));
            }

            // Numeric textboxes
            if ($kendo.hasClass('k-numerictextbox')) {
                setupNumericTextBox($kendo);
            }
        }
    });
}

// #endregion



// #region --- Kendo Drop Downs ---



/**@description Performs setup logic on all Auto-Complete comboboxes.
 */
function setupDropDowns() {
    setupDropDown($('input.k-dropdown'));
}


/**@description Performs setup logic on specific Auto-Complete comboboxes.
 */
function setupDropDown($input) {
    $input.each(function () {
        var popupClass = $(this).attr('data-popup-class');
        var data = $(this).data();

        if (data && popupClass) {
            var kendoDropDownList = data.kendoDropDownList;

            if (kendoDropDownList) {
                kendoDropDownList.list.addClass(popupClass);
            }
        }

        if (data) {

            var kendoDropDownList = data.kendoDropDownList;

            // makes kendo dropdowns open when they're focused by tabbing
            var $dropDownList = $(this).closest("span.k-widget.k-dropdown.k-header");
            if ($dropDownList) {

                $dropDownList.on("mousedown", function (e) {
                    e.preventDefault();
                });

                // controllable by either field, or globally
                $dropDownList.on("focus", function (e) {
                    if (!$dropDownList.hasClass('non-auto')) {
                        kendoDropDownList.open();
                    }
                });
            }
        }
    });
}

// #endregion



// #region --- Kendo Combo Box ---

/**@description Performs setup logic on all comboboxes comboboxes.
 */
function setupComboBoxes() {
    setupComboBox($('input.k-combobox'));
}



/**@description Performs setup logic on specific comboboxes comboboxes.
 */
function setupComboBox($input) {
    $input.each(function () {
        var data = $(this).data();

        if (data) {
            var kendoComboBox = data.kendoComboBox;
            var $dropDownList = $(this).closest("span.k-widget.k-combobox.k-header");

            if (kendoComboBox) {
                kendoComboBox.bind("dataBound", handleComboBoxLoad);

                // makes kendo combo boxes open when they're focused by tabbing
                // controllable by either field, or globally
                kendoComboBox.input.on("focus", function () {
                    if (!$dropDownList.hasClass('non-auto')) {
                        kendoComboBox.open();
                    }
                });
            }

        }
    });
}


/** @description Sets 'empty' class on combobox if no items are loaded.
 */
function handleComboBoxLoad(e) {
    var $input = $(this.element);
    var $comboBox = $input.closest('.k-combobox');

    if (!$comboBox.attr('data-has-loaded')) {

        // Determine if there are any items.
        if (this.dataItems().length) {
            $comboBox.removeClass('empty');
        } else {
            // Hide arrow if there no items
            $comboBox.addClass('empty');
        }
    }

    $comboBox.attr('data-has-loaded', true);
}

// #endregion



// #region --- Custom Autocomplete Combobox ---

/**@description Performs setup logic on all Auto-Complete comboboxes.
 */
function setupAutoCompleteCombos() {
    setupAutoCompleteCombo($('input.autocomplete'));
}

/**@description Performs setup logic on specific Auto-Complete comboboxes.
 */
function setupAutoCompleteCombo($input) {
    $input.each(function () {
        var data = $(this).data();

        if (data) {
            var kendoComboBox = data.kendoComboBox;

            if (kendoComboBox) {
                kendoComboBox.bind("close", handleAutoCompleteComboClose);
                $(this).change(handleAutoCompleteComboChange);
            }
        }
    });
}


/** @description Ensure partial match sticks on tab out
*/
function handleAutoCompleteComboClose(e) {
    var kendoComboBox = e.sender;
    var value = kendoComboBox.value();

    if (kendoComboBox.selectedIndex == -1 && value) {
        e.preventDefault();
        var $first = kendoComboBox.popup.element.find('ul li').first();

        if ($first.length) {
            $first.click();
        }
    }
}


/** @description Ensure that invalid values do not stick if filter excludes all items.
*/
function handleAutoCompleteComboChange() {
    var kendoComboBox = $(this).data().kendoComboBox;
    var value = kendoComboBox.value();

    if (kendoComboBox.selectedIndex == -1 && value) {
        var $first = kendoComboBox.popup.element.find('ul li').first();

        if ($first.length) {
            $first.click();
        } else {
            kendoComboBox.value(null);
        }
    }
}

// #endregion



// #region --- Kendo Numeric Text Boxes --- //

/** @description Performs setup operations on Kendo Numeric Textboxes
*/
function setupNumericTextBoxes() {
    setupNumericTextBox($('.k-numerictextbox'));
}

/** @description Performs setup operations on Kendo Numeric Textboxes
*/
function setupNumericTextBox($input) {
    $input.find('input.k-input')
        .focus(handleNumericTextBoxFocus)
        .blur(handleNumericTextBoxBlur);
}


/** @description Handles focus on a numeric textbox to convert zero back to blank.
*/
function handleNumericTextBoxFocus() {
    // Is actual input field, not the display field?
    if (!$(this).hasClass('k-formatted-value')) {
        // Enabled?
        if (!$(this).attr('disabled') && !$(this).attr('readonly')) {
            // Zero to blank
            if ($(this).val() === "0") {
                $(this).val("");
                $(this).addClass('zeroed-to-null');
            }
        }

        var kendoNumeric = $(this).data().kendoNumericTextBox;

        // Has value that needs decimals?
        if ($(this).val() && kendoNumeric.options.decimals > 0) {
            // Has decimals already?
            if ($(this).val().indexOf(".") === -1) {
                var val = $(this).val() + ".";

                // Append decimal places
                for (var i = 0; i < kendoNumeric.options.decimals; i++) {
                    val = val + "0";
                }

                $(this).val(val);
            }
        }
    }
}


/** @description Handles loss of focus on a numeric textbox to convert nulls back to zero.
*/
function handleNumericTextBoxBlur() {
    if ($(this).hasClass('zeroed-to-null')) {
        var kendoNumeric = $(this).data().kendoNumericTextBox;

        if (!$(this).val()) {
            kendoNumeric.value("0");
        }
    }
}

// #endregion



// #region --- TODO: Review in wake of Kendo Date Picker --- //

// Activates extended functionality of all date time inputs on the page.
function setupDatePickers() {
    setupDatePicker($('input[type=datetime]'));
}

// Extends the functionality of the given date time input.
function setupDatePicker($input) {
    // Disabled to determine if this code is actually needed.
    //$input.datetimepicker({ // Call external plugin
    //    format: 'd/m/Y H:m'
    //});
}

// #endregion



// #region --- Masked Textbox (now obsolete, please use Kendo MaskedTextBox)  ---

function setupMaskedInputs() {
    setupMaskedInput($("input[data-inputmask]"));
}

function setupMaskedInput($input) {
    $input.inputmask();
}

// #endregion



// #region --- Listboxs (now obsolete, please use Kendo MultiSelect)  ---

// Activates extended functionality of multi select listboxes.
function setupListboxes() {
    setupListbox($("select[multiple=multiple]"));
}

// Extends functionality of the given multi select listbox(es).
function setupListbox($list) {
    // Do not apply to Kendo MultiSelects
    if ($list.parent().hasClass('k-multiselect')) {
        return;
    }

    try {
        $list.listbox(); // Call external plugin...

        // Adds quick filtering to listboxes
        $list.each(function () {
            if (!$(this).hasClass("no-search")) {
                $(this).siblings(".lbjs").each(function () {
                    var $input = $('<input class="quick-search" type="textbox" value="" placeholder="Quick Search" />');

                    $(this).prepend($input);

                    $input.keyup(function () {
                        var $list = $(this).siblings(".lbjs-list");
                        var $items = $list.children(".lbjs-item");
                        var search = $(this).val().toUpperCase();

                        $items.removeClass("highlight");

                        if (search) {
                            $items.each(function () {
                                if ($(this).text().toUpperCase().indexOf(search) === 0) {
                                    $(this).addClass("highlight");
                                    $list.scrollTop($list.scrollTop() + $(this).position().top);
                                    return false;
                                }
                            });
                        }
                    });
                });
            } else {
                $(this).siblings(".lbjs").addClass("no-search");
            }
        });
    } catch (ex) {
        // Ignore errors
    }
}


// Reactives the listbox
function refreshListBox($list) {
    $list.next('.lbjs').remove();
    setupListbox($list);
}

// #endregion



// #region --- Kendo Masked Text Boxes --- //

// TODO: This has not been written correctly. It needs to be more selective and scope to a form that is submitting.
/** @description Removes the mask from Kendo masked textbox fields that are required AND empty.
                 This fixes a problem with Kendo where jQuery's validation will validate against the mask instead of the value.
 */
function setupMaskedTextboxesBeforeSubmit() {
    // Loop through each masked textbox that is required.
    $("input[data-role='maskedtextbox'][data-val-required]").each(function () {

        // Get the value of the textbox without the mask using Kendo's raw function.
        var textboxValue = $(this).data("kendoMaskedTextBox").raw();

        // If the required field is empty THEN set the input value as empty.
        if (textboxValue == "") {
            $(this).val("");
        }
    });
}

// #endregion


;
menuHeight = 0;
formChanged = false;
CACHE_COOKIE = '114E2C88-5A0E-477B-B231-A991E939463C';
EMPTY_GUID = '00000000-0000-0000-0000-000000000000';


// Run various setup functions when page is ready.
$(document).ready(function () {
    setupUrl();
    setupMenus();
    setupGrids();
    setupScrollingTables();
    setupInteractiveLinks();
    setupInteractiveMessages();
    setupStickies();
    setupTabs();
    setupSteps();
    setupPopups();
    setupAccordions();
    setupEllipses();
    setupEditableCards();

    // Forms
    setupForms();
    setupDynamicFields();
    setupDynamicDropDowns();

    // TODO: change this to follow setup pattern
    ckEditorValidationFix();

    // Obsolete
    setupListboxes();
    setupMaskedInputs();

    // Center floating content
    centerVertically($('body.no-top-menu #Body'));
});


// events that need to happen at the bottom of the process
function setupPostLoadItems() {
    setupValidation();
    setupInputs();

    // TODO: Suggest calling from setupGrid and placing setupGrid as a post load item.
    setupGridSortIconsAll();
}


/**@description Performs all setup functions on dynamically loaded content (e.g. ajax)
 */
function setupDynamicContent($content) {
    // Validation
    $.validator.unobtrusive.parse($content);
    setupValidator($content.find('form'));

    setupMenu($content.find('.menu-toggle'), true);
    setupGrid($content.find('.k-grid'));
    setupScrollingTable($content.find('table.scroll'));
    setupInteractiveLink($content.find('a.js.confirm, a.js.rename, a.js.dialog, button.js.dialog'));
    setupTemporaryMessage($content.find('.js.message.fade'));
    setupSticky($content.find('.sticky'));
    setupTab($content.find(".k-tabstrip"));
    setupAccordion($content.find('.accordion'));
    setupEllipsis($content.find('.ellipsis, .ellipses'));
    setupEditableCard($content.find('.editable-card'));

    // Forms
    setupForm($content.find('form'));
    setupInput($content.find('input, select, textarea'));
    setupDynamicField($content.find('input.dynamic-field').not('.k-input'));
    setupDynamicDropDown($content.find('.k-dropdown.dynamic-field'));

    // Obsolete
    setupListbox($content.find('select[multiple=multiple]'));
    setupMaskedInput($content.find('input'));
}



// --- Interactive Links --- //

/**@description Activates extended functionality of all links marked as interactive.
 */
function setupInteractiveLinks() {
    setupInteractiveLink($("a.js.confirm, a.js.rename, a.js.dialog, button.js.dialog"));
}

/**@description Applies hooks to links marked as interactive.
 */
function setupInteractiveLink($link) {
    // Confirmation messages
    $link.filter("a.js.confirm").click(function (e) {
        e.preventDefault();
        var href = $(this).attr('href');

        // Dialog
        showConfirmPopup($(this).attr('data-val'), function () {
            window.location = href;
        });
    });

    // Ajax popup dialogs
    $link.filter("a.js.dialog").click(function (e) {
        e.preventDefault();
        getPopup($(this).attr("href"));
    });

    // Ajax popup dialogs
    $link.filter("button.js.dialog").click(function () {
        getPopup($(this).attr("data-url"));
    });
}

// --- --- //



// --- Interactive Messages --- //

// Activates extended functionality of info/validation or temporary messages.
function setupInteractiveMessages() {
    setupTemporaryMessage($(".js.message.fade"));
}

// Fade in temporary messages.
function setupTemporaryMessage($message) {
    $message.hide().fadeIn("slow");
    setTimeout(function () { $message.fadeOut("slow"); }, 5000);
}


// Obsolete
// Display info/validation messages on input focus.
function setupInputMessage($input) {
    $input.focus(function () {
        if ($(this).hasClass("input-validation-error")) {
            $(this).siblings(".field-validation-error").css({ visibility: 'visible' });
        }
        $(this).siblings(".field-info").css({ visibility: 'visible' });
    });
    $input.blur(function () {
        $(this).siblings(".field-validation-error, .field-info").css({ visibility: 'hidden' });
    });
}

// --- --- //



// --- Errors --- //

function handleAjaxError(jqXHR, textStatus, errorThrown) {
    // Remove hidden popups
    var $last = $(".js.popup").last();
    if (!$last.is(':visible')) {
        $last.remove();
    }

    var message = "<p><strong>Status:</strong> " + jqXHR.status + " - " + textStatus + "</p>";

    if (errorThrown) {
        message = message + "<p><strong>Message:</strong> " + errorThrown + "</p>";
    }

    message = message + "<p>There was a problem communicating with the server asynchronously. If this problem continues please contact support.</p>";

    hideLoadingAnimation(false);
    showErrorMessage(message, 'Ajax Problem', 0, true);
}


function handleUnexpectedError() {
    // Remove hidden popups
    var $last = $(".js.popup").last();
    if (!$last.is(':visible')) {
        $last.remove();
    }

    hideLoadingAnimation();
    showMessage('Error', "Unexpected error.");
}

// --- --- //



// ---- Cookies ---- //

// Create a new cookie
function createCookie(name, value, days) {
    var expires = "";
    if (days) {
        var date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        expires = "; expires=" + date.toGMTString();
    }
    else {
        expires = "";
    }

    document.cookie = name + "=" + value + expires + "; path=/";
}


// Get the value of a given cookie
function readCookie(name) {
    var cookies = document.cookie.split(';');
    var fullName = name + "=";

    for (var i = 0; i < cookies.length; i++) {
        var cookie = cookies[i];

        while (cookie.charAt(0) === ' ') {
            cookie = cookie.substring(1, cookie.length);
        }

        if (cookie.indexOf(fullName) === 0) {
            return cookie.substring(fullName.length, cookie.length);
        }
    }

    return undefined;
}


// Delete a cookie by name
function eraseCookie(name) {
    createCookie(name, "", -1);
}

// --- --- //



// ---- Browser cache ---- //

// Determines if the page is cached by the browser.
function isPageCached() {
    return (readCookie(CACHE_COOKIE) === 'true');
}

// Creates a cookie that determines if the page is cached by the browser.
function setCacheCookie() {
    createCookie(CACHE_COOKIE, 'true', 1);
}

// --- --- //



// --- Positioning --- //

// Finds the vertical centre of the given element.
function findVerticalCentre($item) {
    var centre = $item.offset().top;
    centre = centre + ($item.height() / 2)
    return centre;
}


// Vertically centers the given element (element needs to be positioned absolute)
function centerVertically($element) {
    $element.css({ top: '50%', 'margin-top': '-' + ($element.outerHeight() / 2) + 'px' });
}


// Horizontally centers the given element (element needs to be positioned absolute)
function centerHorizontally($element) {
    $element.css({ left: '50%', 'margin-left': '-' + ($element.outerWidth() / 2) + 'px' });
}


// Checks if the given element is visible in the viewport.
function isInView($element) {
    var viewPortTop = $(window).scrollTop();
    var viewPortBottom = viewPortTop + $(window).height();

    var elementTop = $element.offset().top;
    var elementBottom = elementTop + $element.height();

    return ((elementBottom <= viewPortBottom) && (elementTop >= viewPortTop));
}

// --- --- //


// Returns value of a query string paramater by the given name.
function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}


// Prevents client side selection/highlight
function disableSelection($element) {
    $element.attr('unselectable', 'on')
        .css('user-select', 'none')
        .on('selectstart', false);
}



function setupSteps() {
    $('.step form.js').submit(handleStepSubmit);
}


function handleStepSubmit(e) {
    $(this).validate();

    if ($(this).valid()) {
        showLoadingAnimation();
        e.preventDefault();
        var data = $(this).serialize();

        $.ajax($(this).attr('action'), {
            cache: false,
            type: 'POST',
            data: data
        })
        .done(function (response) {
            hideLoadingAnimation(true);
            var $content = $(response);
            var $existing = $('#' + $content.attr('id'));

            if ($existing.length) {
                $existing.replaceWith($content);
            } else {
                var $newStep = $('<div class="step"></div>');
                $('#Content').append($newStep);
                $newStep.append($content);
            }

            var $step = $content.parent();
            if (!$step.hasClass("current")) {
                $('.current.step').removeClass('current').hide();

                $step.fadeIn(function () {
                    $step.addClass('current');
                });

                $('.steps .current').removeClass("current").next().addClass("current");
            }

            var $prevStep = $step.prev('.step');
            if ($prevStep.length) {
                $content.find('.buttons button.back').removeAttr('onclick').click(function (e) {
                    $currentStep = $('.current.step');
                    $prevStep = $currentStep.prev('.step');

                    if ($prevStep.length) {
                        e.stopPropagation();
                        $currentStep.removeClass('current').hide();
                        $('.steps .current').removeClass("current").prev().addClass("current");

                        $prevStep.fadeIn(function () {
                            $prevStep.addClass('current');
                        });
                    }
                });
            }

            $step.find('form.js').submit(handleStepSubmit);
            setupDynamicContent($step);
        })
        .fail(handleAjaxError);
    }
}





// -- TODO: Move and comment -- //

/// Returns the raw data object for the given row of the given table.
function getTableRowData($table, rowId) {
    var result = false;
    var $inputs = $table.find('tr[data-row-id="' + rowId + '"] input');

    $inputs.each(function () {
        var fieldId = $(this).attr('data-field-id');

        if (fieldId) {
            if (!result) {
                result = {};
            }

            var $all = $inputs.filter('input[data-field-id="' + fieldId + '"]');

            if ($all.length > 1) {
                if (!$.isArray(result[fieldId])) {
                    result[fieldId] = [];
                }

                result[fieldId].push($(this).val());
            } else {
                result[fieldId] = $(this).val();
            }
        }
    });

    return result;
}


function sortTableByAscendingOrder($table, column) {
    sortTable($table, column, 1);
}

function sortTableByDescendingOrder($table, column) {
    sortTable($table, column, -1);
}


function sortTable($table, column, orderByFactorNumber) {
    var $rows = $table.find('tbody tr').get();

    $rows.sort(function (a, b) {
        var firstValue = $(a).children('td').eq(column).text().toUpperCase().trim();
        var secondValue = $(b).children('td').eq(column).text().toUpperCase().trim();

        firstValue = firstValue.split('/').reverse().join();
        secondValue = secondValue.split('/').reverse().join();

        if (firstValue < secondValue) {
            return -1 * orderByFactorNumber;
        }

        if (firstValue > secondValue) {
            return 1 * orderByFactorNumber;
        }

        return 0;

    });

    $.each($rows, function (index, row) {
        $table.children('tbody').append(row);
    });
}

// -- -- //


// Ensure Date.toISOString is defined
if (!Date.prototype.toISOString) {
    (function () {
        function pad(number) {
            if (number < 10) {
                return '0' + number;
            }
            return number;
        }

        Date.prototype.toISOString = function () {
            return this.getUTCFullYear() +
              '-' + pad(this.getUTCMonth() + 1) +
              '-' + pad(this.getUTCDate()) +
              'T' + pad(this.getUTCHours()) +
              ':' + pad(this.getUTCMinutes()) +
              ':' + pad(this.getUTCSeconds()) +
              '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) +
              'Z';
        };

    }());
}

// Returns 1 day before the supply date 
function getPreviousDate(dateStr) {
    var parts = dateStr.split("/");
    var currentDate = new Date(parts[2], parts[1] - 1, parts[0]);
    currentDate.setDate(currentDate.getDate() - 1); // ? get 1 day ago
    var previousDateText = currentDate.getDate() + '/' + (currentDate.getMonth() + 1) + '/' + currentDate.getFullYear();
    return previousDateText;
}


// returns a date in the standard string format - for date pickers etc.
function getStandardDateFormat(date) {
    var year = date.getFullYear();
    var month = date.getMonth() + 1;

    if (month < 10) {
        month = "0" + month;
    }

    var day = date.getDate();
    if (day < 10) {
        day = "0" + day;
    }

    return day + "/" + month + "/" + year;
}


// Converts a JSON date (the funky numeric format) to a standard dd/mm/yyy format for passing to date pickers
function convertJSONDateToString(date) {
    if (date != undefined) {
        if (date.length > 6) {
            var workDate = date.substr(6);
            var workDateAsNum = parseInt(workDate);
            return getStandardDateFormat(new Date(workDateAsNum));
        }
    }

    return '';
}

// The CKEditor seems to update the textarea after the MVC validation has already occurred. This function resolves this bug
function ckEditorValidationFix() {
    try {
        for (var i in CKEDITOR.instances) {
            CKEDITOR.instances[i].on('change', function () { CKEDITOR.instances[i].updateElement() });
        }
    }
    catch (err) {
        // CKEditor doesn't exist.
    }
}


// TODO: Suggest moving
// Highlights new messages in the inbox.
function highlightNewMessages() {
    var grid = this;
    grid.tbody.find('>tr').each(function () {
        var dataItem = grid.dataItem(this);
        if (dataItem.LastViewDate == null) {
            $(this).addClass('unread-row');
        }
    })
}


// TODO: -- What is this stuff used for? -- //

// When using the TooltipWrappers.ELLIPSIS_WRAP tooltip wrapper, use this to get the associated item id
function getIdFromToolTipTemplate(id, prefix) {
    var raw = id.replace(prefix, '');
    var len = raw.indexOf('_');
    if (len > 0) {
        raw = raw.slice(0, len);
    }

    return raw;
}

// TODO: tagname needs proper casing
function getTagFromToolTipTemplate(id, prefix, tagname) {
    var raw = prefix + getIdFromToolTipTemplate(id, prefix);
    var div = $("#" + raw);
    return $(div).attr(tagname);
}

// -- -- //


// Converts an Australian postcode into a state
// NOTE: This function will not work for certain postcodes e.g. 2406 is the postcode for: MUNGINDI, NSW;  WEEMELAH, NSW;  MUNGINDI, QLD;
//
/** @description Gets the state from a postcode
 *  @param {int} postCode An Australian Post Code.
 */
function getStateFromPostcode(postCode) {
    var re = /^[0-9]{4}$/;
    if (re.test(postCode)) {
        // NSW
        if (((postCode >= 1000) && (postCode <= 2599)) || ((postCode >= 2620) && (postCode <= 2899)) || ((postCode >= 2921) && (postCode <= 2999))) {
            return "NSW";
        }

        // ACT
        if (((postCode >= 200) && (postCode <= 299)) || ((postCode >= 2600) && (postCode <= 2619)) || ((postCode >= 2900) && (postCode <= 2920))) {
            return "ACT";
        }

        // VIC
        if (((postCode >= 3000) && (postCode <= 3999)) || ((postCode >= 8000) && (postCode <= 8999))) {
            return "VIC";
        }

        // QLD
        if (((postCode >= 4000) && (postCode <= 4999)) || ((postCode >= 9000) && (postCode <= 9999))) {
            return "QLD";
        }

        // SA
        if (((postCode >= 4000) && (postCode <= 4999)) || ((postCode >= 9000) && (postCode <= 9999))) {
            return "SA";
        }

        // WA
        if (((postCode >= 6000) && (postCode <= 6797)) || ((postCode >= 6800) && (postCode <= 6999))) {
            return "WA";
        }

        // TAS
        if (((postCode >= 7000) && (postCode <= 7799)) || ((postCode >= 7800) && (postCode <= 7999))) {
            return "TAS";
        }

        // NT
        if (((postCode >= 800) && (postCode <= 899)) || ((postCode >= 900) && (postCode <= 999))) {
            return "NT";
        }
    }
}


// TODO: What is this? Needs comments. Completely unclear
Number.prototype.format = function (n, x) {
    var re = '\\d(?=(\\d{' + (x || 3) + '})+' + (n > 0 ? '\\.' : '$') + ')';
    return this.toFixed(Math.max(0, ~~n)).replace(new RegExp(re, 'g'), '$&,');
};



function getNumberWithCommas(number) {
    return number.replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
}

// TODO: Since it is  function, recommend renaming to formatPhoneNumber
function formattedPhoneNumber(phoneNo) {

    var number = phoneNo.replace(" ", "");
    number = number.replace("(", "");
    number = number.replace(")", "");

    var standardFormat = "(\\d{4})(\\d{3})(\\d{3})";

    if (isAustralianPhoneNumber(phoneNo)) {
        // Mobile Phone Formatting.
        if (number.startsWith("04")) {
            return number.replace(new RegExp(standardFormat), "$1 $2 $3");
        }

        // International Australian Phone Number.
        var reg = new RegExp("^\\+(?:[0-9] ?){6,14}[0-9]$");
        if (reg.test(number)) {
            return number.replace(new RegExp("(\\d{2})(\\d{1})(\\d{4})(\\d{4})"), "$1 $2 $3 $4");
        }

        // Standard Australian Number
        reg = new RegExp("([(0)][23478]){0,1}[1-9][0-9]{7}");
        if (reg.test(phoneNo)) {
            // Free or Premium Line Numbers.
            if (number.startsWith("1800") || (number.startsWith("190"))) {
                return number.replace(new RegExp(standardFormat), "$1 $2 $3");
            }

            if (number.startsWith("1300")) {   // 1300 Numbers
                return number.replace(new RegExp(standardFormat), "$1 $2 $3");
            }

            // If the number doesn't include the area code.
            reg = new RegExp("(\\d{4})(\\d{4})");
            if (number.startsWith("0") == false) {
                return number.replace(reg, "$1 $2");
            }
            return number.replace(new RegExp("(\\d{2})(\\d{4})(\\d{4})"), "$1 $2 $3");
        }

        // Corporate phone number like Qantas 13 13 13
        reg = new RegExp("1[38][0-9]{4}");
        if (reg.test(phoneNo)) {
            return number.replace(new RegExp("(\\d{2})(\\d{2})(\\d{2})"), "$1 $2 $3");
        }
    }
    return number;
}


function isAustralianPhoneNumber(phoneNo) {
    var isMatch = false;

    // Remove formatting brackets.
    phoneNo = phoneNo.replace("(", "");
    phoneNo = phoneNo.replace(")", "");

    // Remove spaces
    phoneNo = phoneNo.replace(" ", "");

    // Based on https://stackoverflow.com/questions/322493/what-rules-would-you-use-to-validate-an-australian-phone-number

    // Check if 1300 number
    var regex = new RegExp("1300[0-9]{6}");
    if (regex.test(phoneNo)) {
        isMatch = true;
    }

    // Corporate phone number like Qantas 13 13 13
    regex = new RegExp("1[38][0-9]{4}");
    if (regex.test(phoneNo)) {
        isMatch = true;
    }

    // International Australian Number or Regular Australian Number.
    regex = new RegExp("([(0),(+61)][23478]){0,1}[1-9][0-9]{7}");
    if (regex.test(phoneNo)) {
        isMatch = true;
    }

    return isMatch;
}


function setupScrollBar($scrollable) {
    // Create the mac style scroll bar.
    $scrollable.slimScroll({
        height: '100%',
        width: '100%',
        alwaysVisible: false,
        railVisible: false,
        color: '#4f5357',
        railOpacity: 1,
        distance: '0',
    });
}



/** @description Scrolls to a given element in a SlimScroll element.
 * @param {Jquery} $element The element to scroll to.
 */
function slimScrollTo($element) {
    if ($element.length > 0) {
        // The container will be the parent item.
        // TODO: We may want to make this a parameter if we use this elsewhere.
        var $container = $element.parent();

        // Get the position to scroll to. Based on scrollToElement().
        var scrollTo_int = $element.offset().top - $container.offset().top + $container.scrollTop() + 'px';

        // Scroll to the position using SlimScroll's function.
        $container.slimScroll({ scrollTo: scrollTo_int });
    }
}


// --- URL change without reload --- //

// Hash prefix for changes to the browser's URL that did trigger a reload.
var _historyFallbackPrefix = "url=";

/* @description Checks if the URL was changed without first reloading the page but was reloaded manually later.
 * If the URL was changed, redirects the browser to that URL.
 * This is mainly a fallback for older browsers that do not support history.pushState.
 */
function setupUrl() {
    var hash = window.location.hash;
    var location = hash.indexOf(_historyFallbackPrefix);

    if (location > 0) {
        var url = hash.substring(location + 4);
        window.location = url;
    }
}


/* @description Changes the browser's URL without reloading the page.
 */
function changeUrl(url) {
    // Determine if the feature is available.
    if (typeof window.history !== 'undefined' && typeof window.history.pushState !== 'undefined') {
        window.history.pushState(url, '', url);
        return;
    }

    // Fallback
    window.location.hash = _historyFallbackPrefix + url;
}

// --- --- //


/* @description Gets the AnitForgery token from a page.
   @deprecated Anti forgery tokens will now be added automatically to all posts.
 */
function getAntiForgeryToken() {
    var value = $("input[name='__RequestVerificationToken']").val();
    return { '__RequestVerificationToken': value };
}


// https://gist.github.com/scottrippey/3428114
/* @description Adds an antiforgery token to all POSTS
 */
$.ajaxPrefilter(function (options, originalOptions, jqXHR) {
    if (options.type.toUpperCase() === "POST") {
        // We need to add the verificationToken to all POSTs
        var token = $("input[name^=__RequestVerificationToken]").first();
        if (!token.length) return;

        var tokenName = token.attr("name");
        // If no data is being sent to the server THEN add the token as the data.
        if (options.data === undefined) {
            options.data = (options.data ? "&" : "") + token.serialize();
            return;
        }

        // Handle multi part forms e.g. file uploads.
        if (options.contentType == false) {
            // Append to the data string:
            options.data.append("__RequestVerificationToken", token[0].value);
        }
            // If the data is JSON, then we need to put the token in the QueryString:
        else if (options.contentType.indexOf('application/json') === 0) {
            // Add the token to the URL, because we can't add it to the JSON data:
            options.url += ((options.url.indexOf("?") === -1) ? "?" : "&") + token.serialize();
        } else if (typeof options.data === 'string' && options.data.indexOf(tokenName) === -1) {
            // Append to the data string:
            options.data += (options.data ? "&" : "") + token.serialize();
        }
    }
});



// String formatting function 

// First, checks if it isn't implemented yet.
if (!String.prototype.format) {
    String.prototype.format = function () {
        var args = arguments;
        return this.replace(/{(\d+)}/g, function (match, number) {
            return typeof args[number] != 'undefined'
              ? args[number]
              : match
            ;
        });
    };
}


/** @description Converts a given string to a boolean.
 * @param {string} trueOrFalse A string that can be converted to a boolean.
 */
function toBool(trueOrFalse) {

    // Boolean value can be ignored.
    if (typeof trueOrFalse == "boolean") {
        return trueOrFalse;
    }

    // If the value is not a string OR a boolean THEN throw an error.
    if (typeof trueOrFalse != "string") {
        return console.error("Parameter must be a string or boolean.");
    }

    // Convert the string to a boolean.
    trueOrFalse = trueOrFalse.toLowerCase();
    return (trueOrFalse === 'true');
}


/** @description Doubles the size of the kendo drop down
 * @param {string} e sender
 * @see {@link http://docs.telerik.com/kendo-ui/controls/editors/dropdownlist/how-to/appearance/auto-adjust-the-width|Kendo}
 */
function adjustDropDownWidth(e) {
    var listContainer = e.sender.list.closest(".k-list-container");
    listContainer.width(listContainer.width() * 2);
}



/** @description Make a given element draggable.
 * @param {Jquery} $source The element to make draggable.
 * @param {Jquery} $container The element that will be moved around the screen.
 */
function makeDraggable($source, $container){
    // Setup dragging
    $source.css({ cursor: "move" }).mousedown(function (e) {
        var offsetTop = e.pageY - $container.offset().top;
        var offsetLeft = e.pageX - $container.offset().left;

        // Create an overlay element that will appear above the draggable item. This will allow us to access the mouse position when the cursor appears above iframe elements.
        var $overlay = $('<div class="drag-overlay"></div>');
        $container.prepend($overlay);

        $(window).mousemove(function (e) {
            // Prevent the default action from occuring.
            e.preventDefault();
            
            // Calculate the top and left position from the draggable element.
            var top = e.pageY - offsetTop - getWindowScroll();
            var left = e.pageX - offsetLeft;

            // Calculate the max position for the element.
            var maxTop = $(window).height() - 10;
            var maxLeft = $(window).width() - 10;

            // Calculate the min position for the element.

            // The top will always be zero so the user can't move the popup above the window.
            var minTop = 0;
            var minLeft = -$($container).width() + 10;


            // Make sure popup doesn't go off the screen.
            if (top > minTop && left > minLeft && top < maxTop && left < maxLeft){
                $container.css({ 'margin-left': 0, 'margin-top': 0, top: top, left: left });
            }    
        });
    });


    // Stop dragging
    $(window).mouseup(function () {
        // Remove the drag overlay.
        $('.drag-overlay').remove();

        // Unbind the move move event.
        $(this).unbind('mousemove');
    });
};
// ---- Grids ---- //

// A list of grids ready to store config
var _readyGrids = [];


function setupGrids() {
    // TODO: Remove tiles
    setupGrid($('.k-grid, .tiles'));
}

function setupGrid($grid) {
    if ($grid.length === 0) {
        return;
    }
    
    setupGridForeignKeySorting($grid);

    // Saves the current grid config to cookies
    saveGridOptions($grid);

    // Expandable rows -- TODO: review
    $grid.find(".custom-expand").each(function () {
        var $cell = $(this);
        var $clickable = $cell;

        var kendo = $grid.data().kendoGrid;
        if (kendo && !kendo.options.selectable) {
            $clickable = $cell.parent();
        }

        $clickable.click(function (e) {
            if (e.originalEvent !== undefined) {
                expandCollapseRow($cell.parent());
            }
        });
    });


    // Double clicks
    $grid.find('tr, .tile-heading').unbind('dblclick').dblclick(function (e) {
        e.preventDefault();
        var $grid = $(this).closest('.k-grid, .tiles');

        $(this).find('.row-selection').prop('checked', true).change();

        if ($grid.attr('data-grid-default-url')) {
            performSingleRowAction($grid, $grid.attr('data-grid-default-url'));
        }

        var doubleClickFunction = window[$grid.attr('data-grid-default-func')];
        if (typeof doubleClickFunction === 'function') {
            doubleClickFunction();
        }
    });


    // Wait until grid is ready
    var kendoGrid = $grid.data().kendoGrid;
    if (kendoGrid && $.inArray($grid.attr("id"), _readyGrids) !== -1) {

        // Setup filter toggle
        var dataSource = kendoGrid.dataSource;
        var filter = dataSource.filter();
        var $toggle = $('#' + $grid.attr('id') + 'Menu .filter-toggle button');

        if ($toggle.length == 0) {
            // inside a tab
            var $tab = $grid.closest('.k-content');
            $toggle = $tab.find('.filter-toggle button');
        }

        if (filter && !$toggle.hasClass('open')) {
            toggleGridFilter($toggle, $grid);
        }

        // Hide single-entry filter operator drop downs
        var $filterCells = $grid.find('.k-filtercell');
        $filterCells.each(function () {
            var data = $(this).data().kendoFilterCell.operatorDropDown;
            if (data != null && data.ul[0].children.length < 2) {
                $(this).find('.k-dropdown-operator').hide();
            }
        });


        // Setup grouping
        var group = dataSource.group();
        var $toggle = $('#' + $grid.attr('id') + 'Menu .group-toggle a');

        if (group) {
            if (!$toggle.hasClass('open')) {
                toggleGridGrouping($toggle, $grid);
            }
        }

        // Fix Kendo bug
        $grid.find('.k-filter-row .k-group-cell').show();
    }

    // Coloured cells
    $grid.find('td.bool .green').closest('td').addClass('green');
    $grid.find('td.bool .red').closest('td').addClass('red');


    // Setup page sizer
    $grid.find('.k-pager-sizes select option').each(function () {
        $(this).text($(this).text() + LNG_PAGE_SIZE_POSTFIX);
    });

    $grid.find('.k-pager-info').click(function () {
        var $dropDown = $(this).closest('.k-grid').find('.k-pager-sizes .k-dropdown');
        var kendoDropDown = $(this).closest('.k-grid').find('.k-pager-sizes select').data().kendoDropDownList;

        if (!$dropDown.hasClass('open')) {
            $dropDown.addClass('open').click();

            kendoDropDown.bind("close", function () {
                $dropDown.removeClass('open');
            });
        }
    });


    setupRowSelection($grid);

    // Setup Filter
    setupGridFilterEvents($grid);    

    // Setup tooltip for narrow columns
    $grid.find('th').each(function() {
        $(this).attr('title', $(this).text());
    });
}



// --- Grid Options --- //

// Stores the current grid config in cookies
function saveGridOptions($grid) {
    if ($grid.length !== 1) { return; }

    var kendoGrid = $grid.data().kendoGrid;
    if (!kendoGrid) { return; }

    if ($.inArray($grid.attr("id"), _readyGrids) === -1) {
        return;
    }

    var dataSource = kendoGrid.dataSource;
    var page = dataSource.page();
    var size = dataSource.pageSize();
    var sort = dataSource.sort();
    var filter = dataSource.filter();
    var group = dataSource.group();

    if (page) {
        page = kendo.stringify(page);
        createCookie("Grid_Page_" + $grid.attr("id"), page);
    }

    if (size) {
        size = kendo.stringify(size);
        createCookie("Grid_Size_" + $grid.attr("id"), size);
    }

    if (sort) { sort = kendo.stringify(sort); } else { sort = null; }
    if (filter) { fixFilterDates(filter, dataSource); filter = kendo.stringify(filter); } else { filter = null; }
    if (group) { group = kendo.stringify(group); } else { group = null; }

    createCookie("Grid_Sort_" + $grid.attr("id"), sort);
    createCookie("Grid_Filter_" + $grid.attr("id"), filter);
    createCookie("Grid_Group_" + $grid.attr("id"), group);
}


// Updates the grid with the config store in cookies
function getGridOptions($grid) {
    _readyGrids.push($grid.attr("id"));

    var dataSource = $grid.data().kendoGrid.dataSource;
    var page = readCookie("Grid_Page_" + $grid.attr("id"));
    var size = readCookie("Grid_Size_" + $grid.attr("id"));
    var sort = readCookie("Grid_Sort_" + $grid.attr("id"));
    var filter = readCookie("Grid_Filter_" + $grid.attr("id"));
    var group = readCookie("Grid_Group_" + $grid.attr("id"));

    if (page) { page = JSON.parse(page); } else { page = 1; }
    if (size) { size = JSON.parse(size); } else { size = dataSource.pageSize(); }
    if (sort !== undefined) { sort = JSON.parse(sort); } else { sort = dataSource.sort(); }
    if (filter !== undefined) { filter = JSON.parse(filter); } else { filter = dataSource.filter(); }
    if (group !== undefined) { group = JSON.parse(group); } else { group = dataSource.group(); }

    if (size) { 
        return {
            page: page,
            pageSize: size,
            sort: sort,
            filter: filter,
            group: group
        };
    } else { 
        return {
            page: page,
            sort: sort,
            filter: filter,
            group: group
        };
    }
}


// Strip the timezone information saved with the kendo datepicker value
function fixFilterDates(filter, dataSource) {
    if (filter) {
        for (i = 0; i < filter.filters.length; i++) {
            var val = filter.filters[i].value;

            // First check if the filter is valid
            var innerfilter = dataSource.options.schema.model.fields[filter.filters[i].field];

            if (innerfilter != undefined) {
                // Only if it's a date per the datasource
                var isDate = innerfilter.type == 'date';

                if (isDate) {
                    // check formatting
                    var dateWrapper = new Date(val);
                    if (!isNaN(dateWrapper.getDate())) {
                        filter.filters[i].value = dateWrapper;
                    }
                }
            }
        }
    }
}

// --- //



// --- Custom Grid Filters --- //

// setup extended borders for filter fields
function setupGridFilterEvents($grid) {
    var $filter = $grid.find('.k-filter-row');

    $filter.find('.k-input').focus(function () {
        $filter.find('.k-dropdown-operator').addClass('focused');
    });

    $filter.find('.k-input').blur(function () {
        $filter.find('.k-dropdown-operator').removeClass('focused');
    });
}


// Toggles filtering header on the given grid. Removes all filters on toggle off.
function toggleGridFilter($toggle, $grid) {
    var $filter = $grid.find('.k-filter-row');

    if ($filter.is(':visible')) {
        // Close
        $filter.fadeOut();
        $toggle.removeClass('open');
        $toggle.text(LNG_FILTER_OPTIONS);
        clearGridFilter($grid);
    } else {
        // Open
        $filter.fadeIn();
        $toggle.addClass('open');
        $toggle.text(LNG_CLEAR_FILTER);

        // This appears to be the only way to stop kendo putting the tooltip back all the time
        $($filter).find('.k-input').mouseover(function () { $(this).removeAttr('title'); });
    }
}


// Clears all filter on the given grid
function clearGridFilter($grid) {
    var dataSource = $grid.data().kendoGrid.dataSource;
    dataSource.filter(null);
}


// Adds a filter to the given grid field
function addGridFilter($grid, field, operator, value) {
    var dataSource = $grid.data().kendoGrid.dataSource;
    var filters = dataSource.filter();

    if (filters) {
        filters = filters.filters;

        for (var i = 0; i < filters.length; i++) {
            if (filters[i].field == field) {
                filters.splice(i, 1);
            }
        }
    } else {
        filters = [];
    }

    filters.push({ field: field, operator: operator, value: value });

    dataSource.filter(filters);
}


// Removes the filter from the given grid field
function removeGridFilter($grid, field) {
    var dataSource = $grid.data().kendoGrid.dataSource;
    var filters = dataSource.filter();

    if (filters) {
        filters = filters.filters;

        for (var i = 0; i < filters.length; i++) {
            if (filters[i].field == field) {
                filters.splice(i, 1);
            }
        }

        dataSource.filter(filters);
    }
}

// --- //



// --- Custom Grid Grouping --- //

// Toggles grouping header on the given grid. Removes grouping on toggle off.
function toggleGridGrouping($toggle, $grid) {
    var $grouper = $grid.find('.k-grouping-header');

    if ($grouper.is(':visible')) {
        // Close
        $grouper.fadeOut();
        $toggle.removeClass('open');
        $toggle.text(LNG_GROUP_OPTIONS)
        clearGridGrouping($grid);
    } else {
        // Open
        $grouper.fadeIn();
        $toggle.addClass('open');
        $toggle.text(LNG_CLEAR_GROUP)
    }
}


// Clears all grouping on the give grid
function clearGridGrouping($grid) {
    var dataSource = $grid.data().kendoGrid.dataSource;
    dataSource.group(null);
}

// --- //


// --- Custom Grid Sorting --- //

// Bind hover icons so sortable indicator shows up on unsorted columns
// Will automatically work with all tabs and grids on a given page
// Binds a single grid
function setupGridSortIcons($grid) {
    var template = '<span class="k-icon k-i-sort-asc-sm"></span>';

    //Note: styling the parent didn't work. Needed something within the link itself to style
    var unsortedTemplate = '<span class="k-icon k-i-sort-none"></span>';

    $grid.find('th[data-role="columnsorter"]').each(function () {
        $(this).find(".k-link").each(function () {
            $(this).mouseover(function () {

                $(this).find('.k-i-sort-none').each(function () {
                    $(this).remove();
                });

                if ($(this).find("span").length == 0) {
                    $(this).append(template);
                }
            });

            $(this).mouseout(function () {
                if ($(this).parent().attr('aria-sort') == undefined) {
                    $(this).find("span").each(function () {
                        $(this).remove();
                    })
                    $(this).append(unsortedTemplate);
                }
            });

            // preset it
            if ($(this).parent().attr('aria-sort') == undefined) {
                $(this).find("span").each(function () {
                    $(this).remove();
                })
                $(this).append(unsortedTemplate);
            }
        });
    });
}


// Setups up client side foreign key sorting on kendo grids.
function setupGridForeignKeySorting($grid) {
    var kendoGrid = $grid.data().kendoGrid;

    // Check to see if the grid exists.
    if (kendoGrid) {
        // Add custom sort when a change occurs e.g. sorting.
        kendoGrid.dataSource.bind("change", function (e) {
            var isChanged = false;

            if (kendoGrid.dataSource && kendoGrid.dataSource._sort) {
                // Loop through the sort and set the custom sort.
                for (var i = 0; i < kendoGrid.dataSource._sort.length; i++) {

                    // Check to see if a custom compare function has been set.
                    if (!kendoGrid.dataSource._sort[i].compare) {

                        // Loop through each column
                        for (var x = 0; x < this.options.fields.length; x++) {
                            var columnName = this.options.fields[x].field;

                            // Check to see if the column has the same name as the field that is being sorted.
                            if (kendoGrid.dataSource._sort[i].field == columnName) {

                                // Get the values from the field.
                                var values = this.options.fields[x].values;

                                // If the values exist THEN add the custom compare function.
                                if (values) {
                                    kendoGrid.dataSource._sort[i].compare = foreignKeyCompare;
                                    isChanged = true;
                                }
                            }
                        }
                    }

                    // If compare function was added THEN sort the list.
                    if (isChanged) {
                        this.sort(kendoGrid.dataSource._sort);
                    }
                }
            }
        });
    }
}


/** @description Compares two foreign keys
 * @param {string} a The first value to compare.
 * @param {string} b The second value to compare.
 */
function foreignKeyCompare(a, b) {
    // Get the grid.
    var $grid = $(".k-grid");

    var kendoGrid = $grid.data().kendoGrid;
    var sorts = kendoGrid.dataSource._sort;

    // get position of type column
    for (var i = 0; i < sorts.length; i++) {
        var sortFieldName = sorts[i].field;

        // Loop through each column.
        for (var x = 0; x < kendoGrid.options.columns.length; x++) {
            var columnName = kendoGrid.options.columns[x].field;

            // Check to see if we have found the column
            if (sortFieldName == columnName) {
                var values = kendoGrid.options.columns[x].values;

                if (values) {
                    var aValue = a[columnName];
                    var bValue = b[columnName];
                    var aText;
                    var bText;

                    for (var j = 0; j < values.length; j++) {
                        if (values[j].value == aValue) {
                            aText = values[j].text;
                        }

                        if (values[j].value == bValue) {
                            bText = values[j].text;
                        }
                    }

                    // Determine the sort order.
                    if (aText < bText) {
                        return -1;
                    }

                    if (aText > bText) {
                        return 1;
                    }
                }
            }
        }
    }

    return 0;
}

// --- //



// --- Custom row selection --- //

function setupRowSelection($grid) {
    var $selectAll = $grid.find('.select-all');

    // Setup select all.
    $selectAll.change(function () {
        getRowSelectors($grid).prop('checked', $(this).prop('checked'));
        processGridSelection($grid);
    });

    // Setup individual rows
    var $selectors = getRowSelectors($grid);
    $selectors.each(function () {
        // Prevents checkboxes being accidentally highlighted during double clicks.
        disableSelection($(this).parent());

        $(this)
            // Avoid double processing
            .click(function (e) { e.stopPropagation(); })

            // Handle selection
            .change(function () {
                var $grid = $(this).closest(".k-grid");
                var $checkbox = $(this);

                if ($grid.length) {
                    var data = $grid.data().kendoGrid;

                    // Ensure only single selection
                    if (data != null && data.options.selectable && data.options.selectable.toLowerCase().indexOf("single") > -1) {
                        getRowSelectors($grid).each(function () {
                            if ($checkbox.get(0) !== $(this).get(0) && $(this).prop('checked')) {
                                var $owner = $(this).parent().parent();

                                $(this).prop('checked', false);
                                $owner.removeClass("k-state-selected");
                            }
                        });
                    }

                    // Handle changes to grid selections.
                    processGridSelection($grid);
                }
            })

            // Make the whole checkbox cell clickable
            .parent()
                .off("mousedown, click")
                .mousedown(function (e) {
                    e.stopPropagation();
                })
                .click(function (e) {
                    e.stopPropagation();

                    $(this).children('.row-selection').prop('checked', function (i, val) {
                        return !val;
                    }).change();
                });
    });

    if ($selectors.length < 2) {
        $selectAll.hide()
    } else {
        $selectAll.show()
    }


    // The following steps may be deprecating in light of the new design.

    // Ensure checkbox is first
    $grid.find('tr').each(function () {
        var $checkbox = $(this).find('.row-selection, .select-all').parent();
        var $prev = $checkbox.prev();

        while ($prev.length) {
            $prev.before($checkbox);
            $prev = $checkbox.prev();
        }
    });

    // Ensure checkbox is first on filter row
    if ($grid.hasClass('checkboxed')) {
        var $groupCells = $grid.find('.k-filter-row .k-group-cell');
        var $next = $grid.find('.k-filter-row th').first();

        while ($next != null && $next.hasClass('k-group-cell')) {
            $next = $next.next();
        }

        $next.after($groupCells);

        // Ensure there is an empty cell on none-checkbox lines
        $grid.find('.k-grouping-row').each(function () {
            var $first = $(this).find('td').first();
            var $last = $(this).find('td').last();

            $first.before('<td class="empty-cell"></td>');
            $last.attr('colspan', $last.attr('colspan') - 1);
        });
    }
}


// Handles changes to the selected rows of a grid.
function processGridSelection($grid, $buttons) {
    var $rows = getRowSelectors($grid);

    // Highlight the appropraite rows
    $rows.each(function () {
        var $row = $(this).closest('tr');

        if ($(this).is(':checked')) {
            $row.addClass("k-state-selected");
        } else {
            $row.removeClass("k-state-selected");
        }
    });


    // Count selected rows
    var count = getSelectedRows($grid).length;

    // Update select all
    $grid.find('.select-all').prop('checked', count ==  $rows.length);


    // Deprecated
    if ($buttons) {
        $buttons.children('button').each(function () {
            // Dis/en-able buttons that work on a single selected row.
            if ($(this).hasClass('single-item')) {
                if (count === 1) {
                    $(this).prop('disabled', false);
                } else {
                    $(this).prop('disabled', true);
                }
            }

            // Dis/en-able buttons that work on one or more selected rows.
            if ($(this).hasClass('multi-item')) {
                if (count > 0) {
                    $(this).prop('disabled', false);
                } else {
                    $(this).prop('disabled', true);
                }
            }

            // Dis/en-able the select all button
            if ($(this).hasClass('select-all')) {
                if (count === $rows.length) {
                    $(this).prop('disabled', true);
                } else {
                    $(this).prop('disabled', false);
                }
            }
        });
    }

}


// Returns all grid checkboxes.
function getRowSelectors($grid) {
    return $grid.find('.row-selection').not($grid.find('.k-detail-row .row-selection'));
}


// Returns the checkbox of the selected grid rows
function getSelectedRows($grid) {
    return getRowSelectors($grid).filter('.row-selection:checked');
}


// Returns the checkbox of the selected grid row
function getSelectedRow($grid) {
    var $row;
    var count = 0;

    getSelectedRows($grid).each(function () {
        $row = $(this);
        count++;
    });

    if (count === 1) {
        return $row;
    } else {
        return false;
    }
}


// Selects the given row by ID.
function selectRow($grid, rowId) {
    getRowSelectors($grid).filter('.row-selection[data-row-id=' + rowId + ']').prop('checked', true).change();
}


// Selects all row present on the grid
function selectAllRows($grid) {
    getRowSelectors($grid).each(function () {
        $(this).prop('checked', true).change();
    });
}


// Selects all row present on the grid
function deselectRows($grid) {
    getRowSelectors($grid).each(function () {
        $(this).prop('checked', false).change();
    });
}


// Returns the data of the selected grid row
function getSelectedRowGridData($grid) {
    var kendo = $grid.data().kendoGrid;
    var $row = getSelectedRow($grid);

    if (!$row) { return; }

    return kendo.dataItem($row.closest('tr'));
}

// --- //



// --- Custom Loading icons --- //

// Displays a loading animation on the given row (supplied by checkbox)
function showRowLoadingIcon($row) {
    $row.siblings('.loading-icon').fadeIn('slow');
    $row.hide();
}


// Removes the loading animation from the given row (supplied by checkbox)
function hideRowLoadingIcon($row) {
    $row.siblings('.loading-icon').fadeOut('slow', function () { $row.show(); });
}

// --- //


// -- Custom Expand and Collapse --- //

// Toggles the expansion of an expandable row.
function expandCollapseRow($row) {
    if ($row.find('.custom-expand i').hasClass('fa-plus-square-o')) {
        expandRow($row);
    } else {
        collapseRow($row);
    }
}


// Expands an expandable row.
function expandRow($row) {
    var $grid = $row.parents('.k-grid');
    var kendo = $grid.data().kendoGrid;
    kendo.expandRow($row);

    $row.find('.custom-expand i').removeClass('fa-plus-square-o').addClass('fa-minus-square-o');
}



// Collapses an expandable row.
function collapseRow($row) {
    var $grid = $row.parents('.k-grid');
    var kendo = $grid.data().kendoGrid;
    kendo.collapseRow($row);

    $row.find('.custom-expand i').removeClass('fa-minus-square-o').addClass('fa-plus-square-o');
}

// --- //



// Returns the data for the given row (by checkbox)
function getRowGridData($grid, $row) {
    var kendo = $grid.data().kendoGrid;

    if (!$row.is('tr')) {
        $row = $row.closest('tr');
    }

    return kendo.dataItem($row);
}


// Used to display an empty string instead of 'null' in the kendo grid.
function preventNullString(input) {
    if (input !== null) {
        return input;
    } else {
        return "";
    }
}


// Returns the zero based index of the next row. To be used in Kendo Grid Row/Cell Templates.
function getNextRowIndex($grid) {
    var kendoGrid = $grid.data().kendoGrid;
    var counter = $grid.data('next-index');

    if (!counter) {
        counter = 0;
    }

    // Re-index? Reset counter
    if (counter >= kendoGrid.dataItems().length) {
        counter = 0;
    }

    // Store counter against relevant grid.
    $grid.data('next-index', counter + 1);
    return counter;
}



// Sandbox

// Updates the data for the given row (both a full or partial JS array of data can be supplied).
function setLiveRowData($grid, $form, rowId, data) {
    var $row = $grid.find('tr .row-selection[data-row-id="' + rowId + '"]');
    var rowData = $grid.data().kendoGrid.dataItem($row.closest('tr'));

    for (var id in data) {
        var $field = $form.find('div[data-row-id=' + rowId + '] input[data-field-id="' + id + '"]');

        rowData.set(id, data[id]);
        $field.val(data[id]);
    }

    return rowData;
}


// Performs a server action on the selected grid row.
function performSingleRowAction($grid, url) {
    var $row = getSelectedRow($grid);

    if ($row) {
        window.location = url.replace("{0}", $row.val());
    }
}


// Performs a server action on one or more selected grid rows.
function performMultiRowAction($grid, url) {
    var count = 0;
    var hasQueryString = (url.indexOf('?') > -1);

    getSelectedRows($grid).each(function () {
        if (count === 0 && !hasQueryString) {
            url = url + '?ids=';
        } else {
            url = url + '&ids=';
        }

        url = url + $(this).val();

        count++;
    });

    if (count > 0) {
        window.location = url;
    }
}

// Relates to live grids. TODO: Document better.
// Returns the raw data object for the given row of the given form.
function getRowData($form, rowId) {
    var result = false;
    var $inputs = $form.find('div[data-row-id=' + rowId + '] input');
    $inputs.each(function () {
        var fieldId = $(this).attr('data-field-id');

        if (fieldId) {
            if (!result) {
                result = {};
            }

            var $all = $inputs.filter('input[data-field-id="' + fieldId + '"]');

            if ($all.length > 1) {
                if (!$.isArray(result[fieldId])) {
                    result[fieldId] = [];
                }

                result[fieldId].push($(this).val());
            } else {
                result[fieldId] = $(this).val();
            }
        }
    });

    return result;
}


// TODO Document and review

function editGridItem($grid, url) {
    var $row = getSelectedRow($grid);

    getPopup(url.replace('{0}', $row.val()));
}


function deleteGridItems($grid, url, callback) {
    showLoadingAnimation();
    var $rows = getSelectedRows($grid);

    var ids = "";
    $rows.each(function () {
        ids = ids + 'ids=' + $(this).val() + '&';
    });

    $.ajax(url, {
        cache: false,
        type: 'GET',
        data: ids,
        success: function (response) {
            hideLoadingAnimation();

            if (response.IsSuccess) {
                var kendo = $grid.data().kendoGrid;
                var data = response.Data;

                for (var i = 0; i < data.length; i++) {
                    var $row = $grid.find('tr .row-selection[value="' + data[i] + '"]');
                    kendo.removeRow($row);
                }

                if (callback) {
                    callback($grid);
                }
            } else {
                handleUnexpectedError();
            }
        },
        error: handleAjaxError
    });
}


// TODO: Suggest passing jQuery objects as per standard
function toggleAllGridCheckBoxes(grid, button) {
    // taking the grid handle here allows this this work where there are multiple  grids on a page
    // e.g. reconciliation
    var checked = $(button).is(':checked');
    if (checked) {
        selectAllRows($(grid));
    } else {
        deselectRows($(grid));
    }
}


// TODO: Suggest removing and calling setupGridSortIcons($grid) from setupGrid($grid).
// Bind all the grids e.g. on page load
function setupGridSortIconsAll() {
    setupGridSortIcons($('.k-grid'));
};
// JS language constants go here
LNG_NONE = "None";
LNG_PAGE_SIZE_POSTFIX = " per page";
LNG_FILTER_OPTIONS = "Filter Options";
LNG_CLEAR_FILTER = "Clear Filters";
LNG_GROUP_OPTIONS = "Grouping Options";
LNG_CLEAR_GROUP = "Clear Grouping";
LNG_GRP = "Group";
LNG_FUND = "Fund";
LNG_CONFIRM = "Confirm";
LNG_CANCEL = "Cancel";
LNG_SUCCESS = "Success!";
LNG_ERROR = "Error!";
LNG_IN_USE = "Data In Use";
LNG_ACCOUNT_IN_USE = "Account {0} In Use";
LNG_TRANS_IN_USE = "Transaction {0} In Use";
LNG_TRANS_SUMMARY = "added on the {0} for ${1}";
LNG_MBR_IN_USE = "Member in use";
LNG_INS_IN_USE = "Insurance Policy in use";
LNG_UNSAVED_CHANGES = "Any unsaved changes will be lost if you leave this page.";;
// JS link constants go here

LINK_GET_GRPS = 'Groups/GetGroups';
LINK_GRP_LOGIN = 'Groups/Login/';
LINK_OPEN_FUND = '/Group/Funds/Open/';
LINK_FUNDS = '/Group/Funds';;

// ---- Menus ---- //


// Standard setup
function setupMenus() {
    setupTopMenus();

    setupMenu($('#TopMenu a.toggle'), true);
    setupMenu($('#LeftMenu li.menu a.toggle'), false);
    setupMenu($('#Breadcrumbs a.toggle'), true);
    setupMenu($('.menu-toggle'), true);
}


// Adds event handles for the given menu(s).
function setupMenu($toggles, autoCollapse) {
    $toggles.each(function () {
        var $toggle = $(this);
        var $parent = $toggle.parent();
        var $subMenu = $parent.children('ul, .drop-down-menu');

        // Detect toggles
        $toggle.off('click').click(function (e) {
            if ($toggle.is('li')) {
                $parent = $toggle;
            } else if ($toggle.attr('href').substr(0, 1) == '#') { // Is anchor?
                e.preventDefault();
            }

            // Toggle menu
            if ($parent.hasClass('expanded')) {
                collapseMenu($parent);
            } else {
                expandMenu($parent);
            }
        });


        // Determine if the drop down should close automatically when focus moves
        if (autoCollapse) {
            $parent.focusin(function (e) {
                // Is focus on child element?
                if (!$toggle.is(e.target) && !$parent.hasClass('expanded')) {
                    // Prevent collapse
                    $parent.addClass('expanded');
                    $subMenu.stop(false, true, true).show();
                }
            });

            $parent.focusout(function (e) {
                collapseMenu($parent);
            });
        }
    });
}


// Expands the given drop down menu
function expandMenu($parent) {
    var $subMenu = $parent.children('ul, .drop-down-menu');

    // Detect if popup will be outside viewport
    $subMenu.show().css({ opacity: 0 });

    // Find first scrolling container
    var $container = $subMenu.parent();
    while (!$container.is('body')) {
        var overflow = $container.css('overflow-y');

        if (overflow == 'scroll' || overflow == 'auto') {
            break;
        }

        $container = $container.parent();
    }

    // If drop down is not inside a scrolling container, get viewport instead.
    if ($container.is('body')) {
        $container = $(window);
    }

    // Calculate bottom and right edge of the scrolling viewport.
    var offset = $container.offset();
    var containerRight = $container.width();
    var containerBottom = $container.height();

    if (offset) {
        containerRight = containerRight + offset.left;
        containerBottom = containerBottom + offset.top;
    }

    // Compare bottom and right edge of the drop down to the viewport.
    var subMenuRight = $subMenu.offset().left + $subMenu.width();
    var subMenuBottom = $subMenu.offset().top + $subMenu.height();

    if (subMenuRight > containerRight && !$subMenu.hasClass('leftwards')) {
        $subMenu.addClass('leftwards');
    }

    if (subMenuBottom > containerBottom && !$subMenu.hasClass('upwards')) {
        $subMenu.addClass('upwards');
    }

    // Reset to inherited styling
    $subMenu.css({ 'top': '', 'bottom': '' });

    // Ensure drop down doesn't cover the trigger button
    if ($subMenu.hasClass('upwards')) {
        if ($subMenu.css('bottom') == '0px') {
            $subMenu.css({ 'bottom': $parent.height() - 1 });
        }
    } else {
        if ($subMenu.css('top') == '0px') {
            $subMenu.css({ 'top': $parent.height() - 1 });
        }
    }

    // Trigger animation
    $subMenu.css({ display: 'none', opacity: 1 });
    $parent.addClass('expanded');
    $subMenu.slideDown('fast');
}


// Collapses the given drop down menu
function collapseMenu($parent) {
    var $subMenu = $parent.children('ul, .drop-down-menu');

    if (!$subMenu.is(':visible')) {
        return;
    }

    $subMenu.css({ display: 'block' });
    $parent.removeClass('expanded');
    $subMenu.slideUp('fast');
}


// Populates the main header's menus.
function setupTopMenus() {
    setupNotifications()

    // Load group menu and breadcrumbs
    var $groupMenu = $('#GroupMenu');
    var $groupMenuList = $groupMenu.find('ul');
    var $groupCrumb = $('#Breadcrumbs li').eq(1).find('ul');
    var $currentGroupItems = $groupMenuList.find('li');

    var $fundMenu = $('#FundMenu');
    var $fundMenuList = $fundMenu.find('ul');
    var $currentFundItems = $fundMenuList.find('li');

    // If the Group Menu element exists we are in an area that can show Group and Fund selections.
    if ($groupMenu.length > 0) {
        $groupCrumb.empty();
        $.ajax(masterUrl + LINK_GET_GRPS,
            {
                cache: false,
                dataType: "jsonp",
                jsonp: "callback",
                success: function (data) {
                    var groups = data.Data;
                    $groupMenuList.html(null);

                    // Show group list?
                    if (groups.length > 1) {
                        $groupMenu.show();

                        for (var i = 0; i < groups.length; i++) {
                            var row = '<li><a href="' + masterUrl + LINK_GRP_LOGIN + groups[i].Id + '">' + groups[i].Name + '</a></li>';
                            $groupMenuList.append($(row));
                            $groupCrumb.append($(row));
                        }

                        $groupMenuList.append($currentGroupItems);

                        // Show single link?
                    } else if (groups.length == 1) {
                        var $body = $('body');

                        // Don't show a single link in these cases...
                        if ($body.attr('data-is-fund-area') == "True") {
                            return;
                        }

                        // Convert from a menu to a single link if the user has Group Access.
                        if (groups[0].HasGroupAccess) {
                            // Non-list
                            $groupMenu.show();
                            var $groupLink = $groupMenu.find('a.toggle');
                            $groupMenuList.remove();
                            $groupLink.removeClass('toggle');
                            $groupLink.addClass('link');
                            $groupLink.text(LNG_GRP);
                            $groupLink.attr('href', masterUrl + LINK_GRP_LOGIN + groups[0].Id);
                        } else {
                            $groupMenu.remove();
                        }

                        // When logged onto a Slave, the fund list has already been loaded.
                        // On the Master if there is only one group we can assume what funds to display.
                        if ($body.attr('data-is-slave') == "False") {
                            // Show fund list?
                            if (groups[0].Funds.length > 1) {
                                $fundMenu.show();

                                for (var i = 0; i < groups[0].Funds.length; i++) {
                                    var row = '<li><a href="' + groups[0].ServerUrl + LINK_OPEN_FUND + groups[0].Funds[i].Id + '">' + groups[0].Funds[i].Name + '</a></li>';
                                    $fundMenuList.append($(row));
                                }

                                $fundMenuList.append($currentFundItems);
                                $fundMenuList.find('.separated a').attr('href', groups[0].ServerUrl + LINK_FUNDS);

                                // Show single item?
                            } else if (!$groupMenu.is(":visible") && groups[0].Funds.length == 1) {
                                // Non-list
                                $fundMenu.show();
                                var $fundLink = $fundMenu.find('a.toggle');
                                $fundMenuList.remove();
                                $fundLink.removeClass('toggle');
                                $fundLink.addClass('link');
                                $fundLink.text(LNG_FUND);
                                $fundLink.attr('href', groups[0].ServerUrl + LINK_OPEN_FUND + groups[0].Funds[0].Id);
                            }
                        }
                    }
                },
                error: handleAjaxError
            }
        );
        setupZendeskSupportButton();
    }
}


// Populates the notification menu on the top header.
function setupNotifications() {
    var $notifications = $('#Notifications');
    var unread = $notifications.find('ul').first().data('notification-count');

    if (unread > 0) {
        var $urgent = $notifications.find('.urgent');
        var $toggle = $notifications.find('.toggle');
        var $count;
        var $seeAll = $notifications.find('.see-all').first().find('a').first();

        if ((unread - 5) > 0) {
            $seeAll.text('See All ' + (unread - 5) + ' more');
        }
        else {
            $seeAll.text('See All');
        }

        if (unread > 9) {
            $count = $('<span class="unread-count">9+</span>');
        }
        else {
            $count = $('<span class="unread-count">' + unread + '</span>');
        }

        if ($urgent.length > 0) {
            $count.addClass('urgent');
        }

        $toggle.addClass('unread');
        $toggle.append($count);
    }
}


/** @description Adds the event handler for the Zendesk widget.
 */
function setupZendeskSupportButton() {
    // Add an event handler to the help button.
    $('button.support-button').click(function (e) {
        zE.activate({ hideOnClose: true });
    });
}

// TODO: this needs to be called after the Zendesk content/iframe is loaded.
// Used to hide the zendesk logo.
// https://practicalsystems.atlassian.net/browse/PALSI-596
function setupZendeskPopup() {
    var $div = $("#helpCenterForm");
    var observer = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            if (mutation.attributeName === "style") {
                var attributeValue = $(mutation.target).prop(mutation.attributeName);
                // Check if finished animation
                if (attributeValue.top == '-9999px') {
                    // Hide the menu if it is visible.
                    $('#zFooter').remove();

                }
                if (mutation.target.className.includes('active')) {
                    if ($('#zFooter').length==0) {
                        var $cover = $("<div id='zFooter' style='display:none;'></div>");
                        $("body").append($cover);
                        //  $cover.fadeIn(300);
                        $cover.show();
                    }
                }
            }
        });
    });
    observer.observe($div[0], {
        attributes: true,
        attributeFilter: ["style"]
    });
};
// ---- Dialogs/Popups ---- //

/*
 @description The timer that is used for showLoadingAnimationAfter. 
 @global */
var _loadingAnimationTimer;

// Setup pre-displayed popups.
function setupPopups() {
    $(window).resize(function () {
        centerVertically($('.js.popup'));
    });
}


/**@description Displays a mask over the web page to prevent interaction.
 * 
 * @notes REMOVED: Modified to be a bit pessimistic as in repeated uses of a dialog it was intermittently not showing the overlay
 * @TODO These changes are will cause other problems. I have removed them, we will need to work out another way to solve the above bug.
 */
function showOverlay() {
    $('.js.overlay').stop(true, true);
    fadePopups();

    var $overlay = $('.js.overlay');

    if (!$(".js.overlay").length) {
        $overlay = $('<div class="js overlay"></div>');
        $overlay.hide();

        $("body").append($overlay);
    }

    $overlay.fadeIn();

    return $overlay;
}


/**@description Removes the overlay
 */
function hideOverlay() {
    $('.js.overlay').stop(true, true).fadeOut(function () {
        $(this).remove();
    });
}



/**@description Displays a loading animation
 */
function showLoadingAnimation() {
    $('.js.loading').stop(true, true);

    var $animation = $('.js.loading');

    if (!$animation.length) {
        $animation = $('<div class="js loading"><img src="' + masterUrl + 'Content/Images/loading.gif" alt=""/></div>');
        $animation.hide();
        $("body").append($animation);
    }

    showOverlay();
    $animation.fadeIn();
    centerVertically($animation);

    return $animation;
}


/**@description Removes the loading animation
 */
function hideLoadingAnimation(removeOverlay) {
    if (_loadingAnimationTimer) {
        clearTimeout(_loadingAnimationTimer);
    }

    $('.js.loading').stop(true, true).fadeOut(function () {
        $(this).remove();

        if (!$('.js.popup').not('.below').length) {
            $('.js.popup.below').last().removeClass('below');
        }
    });

    if (removeOverlay) {
        hideOverlay();
    }
}


/**@description Waits for a period of time and then shows the loading animation.
 */
function showLoadingAnimationAfter(milliseconds) {
    _loadingAnimationTimer = setTimeout(function () {
        showLoadingAnimation();
    }, milliseconds);
}



/**@description Displays popup returned from the given URL.
 */
function getPopup(url, callback) {
    showLoadingAnimation();

    // Get dialog from server
    $.ajax(
    {
        url: url,
        cache: false,
        success: function (data) {
            var $dialog = $(data);

            if (!$dialog.hasClass('popup')) {
                if (data.Message) {
                    if (data.IsSuccess) {
                        showMessage(LNG_SUCCESS, data.Message);
                    } else {
                        showErrorMessage(data.Message);
                    }
                } else {
                    showErrorMessage("Invalid popup content sent from the server.");
                }
            }

            hideLoadingAnimation();
            showPopup($dialog, false);

            if (callback) { callback($dialog); }
        },
        error: handleAjaxError
    });
}


/**@description Displays the given popup with a dark overlay behind
 * @param {JQuery} $popup The popup to display.
 * @param {JQuery} $cancel The button that will cancel the popup.
 * @param {function} callback A function that will called when the popup closes.
 */
function showPopup($popup, $cancel, callback, isInstant) {
    // Insert overlay and popup
    var $overlay = showOverlay();

    // For ajax posted dialogs, the response won't necessarily come back as a DOM object. Convert if needed.
    if (typeof $popup === 'string' || $popup instanceof String) {
        $popup = $($popup);
    }

    $('body').append($popup);

    // Setup close button
    var closeIcon = masterUrl + "Content/Images/cross-light.svg";
    var $close = $('<div class="close"><img alt="X" src="' + closeIcon + '"></div>');

    // Show popup
    if (isInstant) {
        $popup.show();
    } else {
        $popup.hide().fadeIn('fast');
    }

    $popup.removeClass('below');
    centerVertically($popup);

    setupDynamicContent($popup);

    // Cancel button provided?
    if (!$cancel) {
        // Find common cancel buttons
        $cancel = $popup.find('.form-buttons .cancel, .mini-links .cancel');
    }

    // Has a cancel button?
    if ($cancel.length) {
        // Link cross to cancel button
        $close.click(function () {
            $cancel.click();
        });
    } else {
        // Otherwise cross is only close button available.
        $cancel = $close;
    }

    // If the popup is a popup-notification THEN don't show the close button.
    // This is used for the success and error dialogs.
    if (!$popup.hasClass('popup-notification')) {
        $popup.append($close);
    }


    // Bind
    $cancel.click(function (e) {
        if (!$popup.hasClass('below')) {
            e.stopPropagation();

            if (callback) {
                if (callback($popup)) {
                    removePopup($popup);
                }
            } else {
                removePopup($popup);
            }
        }
    });


    setupOverlayClick($popup, $overlay, $cancel);

    // Setup dragging
    makeDraggable($popup.find('.page-header'), $popup);

    // Setup tabing
    focusPopup($popup);

    // Append an empty but tabbable element to detect when the focus reaches the end of the popup.
    var $focusTrap = $('<span tabindex="0"></span>');
    $popup.append($focusTrap);
    $focusTrap.focusin(function (e) {
        focusPopup($popup);
    });
}


/**@description Removes (or hides) the given popup.
 * @param {JQuery} $popup The popup to fade out and remove.
 * @param {function} [callback] Optional. A function that will called when the popup closes.
 */
function removePopup($popup, callback) {
    if ($('.js.popup').not('.hide:hidden').length < 2) {
        hideOverlay();
    }

    if (_loadingAnimationTimer) {
        clearTimeout(_loadingAnimationTimer);
    }

    $popup.fadeOut(function () {
        // Hide class marks popups that shouldn't be removed but hidden instead
        if (!$(this).hasClass('hide')) {
            $(this).remove();
        }

        // If no loading animation, show next top most popup
        if (!$('.js.loading').length) {
            $('.js.popup.below').last().removeClass('below');
        }

        if (callback) { callback(); }
    });
}


/**@description Gives focus to the popup or its first input.
 */
function focusPopup($popup) {    
    var $firstInput = $popup.find(':input').first();

    if ($firstInput.length) {
        $firstInput.focus();
    }
}


/**@description Moves visible popups to beneath to the overlay.
 */
function fadePopups() {
    $('.js.popup:visible').addClass('below');
}


/**@description Enable "background click to cancel" on popups that don't contain input fields or have 'non-modal' class.
 */
function setupOverlayClick($popup, $overlay, $cancel) {
    if (($popup.find("input:not([type=hidden])").length == 0) || ($popup.hasClass("non-modal"))) {
        $overlay.click(function () { $cancel.click(); });
    }
}



/**@description Display a message to the user.
 */
function showMessage(title, message) {
    var $popup = $(
        '<div class="js popup c3 g2">' +
            '<h2 class="page-header">' + title + '</h2>' +
            '<p class="container footer">' + message + '</p>' +
        '</div>');
    showPopup($popup);
}


/**@description Displays a success message popup to the user.
 * @param {string} message Main message to inform the user.
 * @param {string} [title] Optional. Heading text.
 * @param {int} [timeout] Number of miliseconds to show the popup for. 0 for infinite. Default is 4000.
 */
function showSuccessMessage(message, title, timeout) {
    if (!title) { title = LNG_SUCCESS; }

    var $popup = $(
        '<div class="message js popup c3 g2">' +
            '<img class="message-icon" src="' + masterUrl + 'Content/Images/success-green.svg" />' +
            '<h3>' + title + '</h3>' +
            '<p>' + message + '</p>' +
        '</div>');
    showPopup($popup);

    // Setup timeout
    if (timeout === 0) { return }
    if (!timeout) { timeout = 3000; } // One second was way too quick.

   _loadingAnimationTimer = setTimeout(function () {
        removePopup($popup);
    }, timeout);
}


/**@description Displays an error message popup to the user.
 * @param {string} message Main message to inform the user.
 * @param {string} [title] Optional. Heading text.
 * @param {int} [timeout] Number of miliseconds to show the popup for. 0 for infinite. Default is 0.
 * @param {bool} [useCustomMarkup] If true the message is injected as is, otherwise it is wrapped in a tag.
 */
function showErrorMessage(message, title, timeout, useCustomMarkup) {
    if (!title) { title = LNG_ERROR; }

    var $popup = $(
        '<div class="message js popup c3 g2">' +
            '<img class="message-icon" src="' + masterUrl + 'Content/Images/error.svg" />' +
            '<h3>' + title + '</h3>' +
        '</div>');

    if (useCustomMarkup) {
        $popup.append(message);
    } else {
        $popup.append('<p>' + message + '</p>');
    }

    showPopup($popup);

    // Setup timeout
    if (!timeout) { return; }

    _loadingAnimationTimer = setTimeout(function () {
        removePopup($popup);
    }, timeout);
}


/**@description Displays an error message popup populated with messages from the given list.
 */
function showErrorMessages(messages) {
    // Display a popup with a list of error messages.
    var $messages = $('<ul />');

    for (var i = 0; i < messages.length; i++) {
        $messages.append($('<li />').text(messages[i]));
    }

    showErrorMessage($messages, null, 0, true);
}



/**@description Displays an locked warning message popup to the user.
 * @param {string} [title] Optional. Heading text.
 * @param {object} result Validation Response.
 */
function showLockedMessage(title, result) {
    if (!title) { title = LNG_IN_USE; }
    var message = "";

    // Deprecated: String passed to result.
    if (typeof result === 'string' || result instanceof String) {
        message = '<p>' + result + '</p>';
    } else {
        // Sub Copy
        if (result.SubCopy) {
            message = "<p class='left'>" + result.SubCopy + "</p>";
        }

        // Messages
        if (result.Validation) {
            if (result.Validation.Errors) {
                message = message.concat('<ul>');

                for (var i = 0; i < result.Validation.Errors.length; i++) {
                    message = message.concat('<li>').concat(result.Validation.Errors[i].Value).concat('</li>');
                }

                message = message.concat('</ul>');
            }
        }
    }

    var $popup = $(
        '<div class="message js popup c3 g2">' +
            '<img class="message-icon" src="' + masterUrl + 'Content/Images/locked-grey.svg" />' +
            '<h3>' + title + '</h3>' +
             message +
        '</div>');

    showPopup($popup);
}



/**@description Ask the user to confirm an operation.
 * @param {string} message Main message to inform the user of what they are confirming.
 * @param {function} confirmCallback Function called on confirmation.
 * @param {object} [confirmPostback] Optional. Data passed to the confirmCallback function.
 * @param {function} [cancelCallback] Optional. Function called on cancel.
 * @param {object} [cancelPostback] Optional. Data passed to the cancelCallback function.
 * @param {string} [title] Optional. Heading text.
 * @param {string} [subTitle] Optional. Adds a subtitle to the dialog.
 */
function showConfirmPopup(message, confirmCallback, confirmPostback, cancelCallback, cancelPostback, title, subTitle) {
    if (!title) { title = LNG_CONFIRM; }

    var $popup = $(
        '<div class="js popup c3">' +
            '<p class="container">' + message + '</p>' +
        '</div>');

    var $heading = $(
        '<div class="page-header">' +
            '<h2>' + title + '</h2>' +
        '</div>');

    if (subTitle) {
        $heading.append('<p>' + subTitle + '</p>');
    }

    var $formButtons = $('<div class="form-buttons fill"></div>');
    var $confirm = $('<button class="save" type="button">' + LNG_CONFIRM + '</button>');
    $formButtons.append($confirm);

    var $miniLinks = $('<div class="mini-links"></div>');
    var $cancel = $('<button class="cancel link" type="button">' + LNG_CANCEL + '</button>');
    $miniLinks.append($cancel);

    $popup.prepend($heading);
    $popup.append($formButtons);
    $popup.append($miniLinks);

    showPopup($popup, $cancel);

    // Confirm
    $confirm.click(function () {
        removePopup($popup);
        confirmCallback(confirmPostback);
    });

    // Cancel callback (if any)
    if (cancelCallback != null) {
        cancel.click(function () {
            cancelCallback(cancelPostback);
        });
    }
}


/**@description Ask the user to confirm an operation
 */
function showYesNoPopup(message, yesCallback, yesPostback, noCallback, noPostBack) {
    var $popup = $(
        '<div class="js popup c2">' +
            '<div class="page-header">' +
                '<h2>Confirm</h2>' +
                '<p>' + message + '</p>' +
            '</div>' +
            '<div class="footer fill form-buttons"></div>' +
        '</div>');
    var $confirm = $('<button type="button">Yes</button>');
    var $cancel = $('<button class="grey" type="button">No</button>');
    $popup.find('.form-buttons').append($confirm).append($cancel);

    showPopup($popup, $cancel);

    // Yes
    $confirm.click(function () {
        removePopup($popup);

        if (yesCallback !== null) {
            yesCallback(yesPostback);
        }
    });

    // No
    $cancel.click(function () {
        if (noCallback != null) {
            noCallback(noPostback);
        }
    });
}


/**@description handles display and submission of standard ajax popup dialogs
 * @param {string} actionType Get or set method for submissions
 * @param {string} url Link to the location of the dialog to show
 * @param {object} data to submit in json format
 */
function showCustomPopup(actionType, url, data) {
    showLoadingAnimation();

    $.ajax(
         {
             type: actionType,
             url: url,
             data: data
         })
         .done(function (response) {

             var $popup = $(response);
             var $cancel = $popup.find(".mini-links .cancel, div.close");
             if (!$cancel.length) {
                 $cancel = false;
             }

             showPopup($popup, $cancel);
             hideLoadingAnimation();

         })
         .fail(handleAjaxError);
};
// ---- Scroll ---- //

// Get current absolute window scroll position
function getWindowScroll() {
    return window.pageYOffset ||
           document.body.scrollTop ||
           document.documentElement.scrollTop || 0;
}


// Scrolls the windows to the given position.
function scrollWindow(pos) {
    $('html,body').animate({ scrollTop: pos }, 1000, function () {
        if (this.nodeName === "BODY") {
            window.scrollTo(0, pos); // Attempt to ensure scroll (cross browser)
        }
    });
}


/** @description Scrolls to the position of an element.
 * @param {string} $container The object that holds the scrollable elements 
 * @param {bool} $element The element to scroll to.
 */
function scrollToElement($container, $element) {
    if ($element.length > 0) {
        $container.animate({
            scrollTop: $element.offset().top - $container.offset().top + $container.scrollTop()
        });
    }
}


/** @description Stores the position of the scroll for the given scrollable element.
 */
function recordElementScroll($element) {
    var scroll = $element.scrollTop();

    $element.data("previousScroll", scroll);

    return scroll;
}


/** @description Restores the position of the scroll for the given scrollable element to the value previously recorded for it.
 */
function restoreElementScroll($element) {
    var scroll = $element.data("previousScroll");

    if (scroll) {
        $element.scrollTop(scroll);
    }
}


/** @description Reset the position of the scroll for the given scrollable element to the top.
 */
function resetElementScroll($element) {
    $element.data("previousScroll", 0);
}


// --- --- //;
// ---- Stickies ---- //
_pauseStickies = false;

// Activates functionality of all sticky elements on the page.
function setupStickies() {
    setupSticky($(".sticky"));

    $(window).scroll(function () {
        updateStickies();
    }).resize(function () {
        calculateStickies();
    });
}

// Configures the given sticky elements
function setupSticky($sticky) {
    $sticky.each(function () {
        var $wrap = $('<div class="sticky-wrap"></div>');
        $(this).wrap($wrap);
    });

    calculateStickies();
}


/**@description Calculates the position of the sticky header or footer
 */
function calculateStickies() {
    resetSlipperies();

    $('.sticky:visible').each(function () {
        var $sticky = $(this);
        var $wrap = $sticky.parent('.sticky-wrap');
        var isStuck = $sticky.hasClass("stuck");

        // Unstick
        if (isStuck) {
            $sticky.removeClass("stuck")
        }

        // Prep
        $sticky.attr("data-val-offset", $sticky.offset().top);
        $wrap.height($sticky.outerHeight(true));

        if (isStuck) {
            // Recalulate
            var width = $wrap.width();
            var left = $sticky.offset().left;
            var right = $("body").width() - left - width;

            $sticky
                .addClass("stuck")
                .css({ 'padding-left': left, 'padding-right': right })
                .width($("body").width() - left - right);
        }
    });


    updateSlipperies();
}


/**@description Updates the position of sticky headers and footers
 */
function updateStickies() {
    if (_pauseStickies) {
        return;
    }
    $('.sticky:visible').each(function () {
        var $sticky = $(this);
        var $wrap =  $sticky.parent('.sticky-wrap');
        var offset = $sticky.attr("data-val-offset");
        var viewPortTop = $(window).scrollTop();
        var viewPortBottom = viewPortTop + $(window).height();

        // In view?
        if (($sticky.hasClass("top") && viewPortTop < offset) || // Top sticky
            (!$sticky.hasClass("top") && viewPortBottom > offset)) { // Bottom sticky

            if ($sticky.hasClass("stuck")) {
                // Unstick
                $sticky.fadeOut('fast', function () {
                    $sticky
                        .css({ 'padding-left': 'inherit', 'padding-right': 'inherit', width: 'inherit' })
                        .removeClass("stuck")
                        .fadeIn("fast");
                });
            }
        } else {
            // Not already stuck?
            if (!$sticky.hasClass("stuck")) {
                // Calculate horizontal positioning
                var width = $wrap.width();
                var left = $sticky.offset().left;
                var right = $("body").width() - left - width;

                // Stick
                $sticky.fadeOut("fast", function () {
                    $sticky.fadeIn("fast");

                    if (!$sticky.hasClass('slippery')) {
                        $sticky
                            .css({ 'padding-left': left, 'padding-right': right })
                            .width($("body").width() - left - right)
                            .addClass("stuck");
                    }
                });
            }
        }
    });
}


/**@description Returns slippery buttons to a non-slippery state.
 */
function resetSlipperies() {
    var $buttons = $('.slippery.form-buttons');

    if ($buttons.hasClass('slippery')) {
        $buttons.removeClass('slippery');
        $buttons.addClass('sticky');
        $buttons.css({ 'top': 'inherit' });
    }
}


/**@description Updates the position of slippery buttons.
 */
function updateSlipperies() {
    resetSlipperies();

    // Assume only one instance
    var $buttons = $('.sticky.form-buttons');

    if ($buttons.length && !$buttons.hasClass('stuck')) {
        var bodyHeight = $('body').height();
        var offset = $buttons.offset().top;
        var height = $buttons.outerHeight();
        var top = bodyHeight - offset - height;

        if (top > 0) {
            $buttons.removeClass('sticky');
            $buttons.addClass('slippery');
            $buttons.css({ 'top': top, 'padding-left': 'inherit', 'padding-right': 'inherit' });
        }
    }

    updateStickies();
}


// TODO: Luke
function setupStickyHeader() {
    var $header = $('#Header');
    var $wrap = $('<div class="header-wrap"></div>');
    $wrap.height($header.height() + 1);
    $('#Header').wrap($wrap);
}


// TODO: Luke
function updateStickyHeader() {
    var maxHeight = 89;
    var minHeight = 53;
    var maxLogoPadding = 18;
    var maxIconPadding = 36;
    
    var $header = $('#Header');
    var $headerWrap = $('.header-wrap');
    var $logo = $('#Logo a');
    var $icons = $('#Profile a, #Notifications a, #GroupMenu a');
    var height = $header.height();
    var viewPortTop = $(window).scrollTop();

    if (viewPortTop > 0) {
        $header.addClass('fixed');

        // Recalc header height
        height = height - viewPortTop;
        if (height < minHeight) { height = minHeight; }
        $header.height(height);
        $headerWrap.height(height + 1);

        // Recalc logo padding
        var logoPadding = maxLogoPadding - ((maxHeight - height) / 2);
        if (logoPadding < 0) { logoPadding = 0; }
        $logo.css({ 'padding': logoPadding + 'px 0' });

        // Recalc icon padding
        var iconPadding = maxIconPadding - ((maxHeight - height) / 2);
        if (iconPadding < 0) { iconPadding = 0; }
        $icons.css({ 'padding': iconPadding + 'px 30px' });

    } else {
        $header.removeClass('fixed');
        $header.css({ 'height': maxHeight });
        $logo.css({ 'padding': maxLogoPadding + 'px 0' });
        $icons.css({ 'padding': maxIconPadding + 'px 30px' });
    }
};
/**
 * @file A collection of Utilities for tables.
 */


var _scrollingTableTimer;

/** @description Performs special changes to all tables on the page that require special scrolling.
 */
function setupScrollingTables() {
    setupScrollingTable($('table.scroll'));

    $(window).resize(function () {
        if (_scrollingTableTimer) {
            clearTimeout(_scrollingTableTimer);
        }

        _scrollingTableTimer = setTimeout(setupScrollingTables, 100);
    });
}


/** @description Performs special changes to a table to make the rows scrollable with a fixed header and footer.
 */
function setupScrollingTable($table) {
    $table.each(function() {
        // Reset the styling
        $(this).css({ 'display': '' });
        $(this).find('th, td').css({ 'width': '' });
        $(this).find('tbody').css({ 'display': '', 'overflow-y': '', 'border-right': '', 'border-bottom': '', 'height': '' });
        $(this).find('tr').last().find('th, td').css({ 'border-bottom-width': '' });
        $(this).find('.scroll-spacer').remove();
        resetSlipperies();

        // Try to detect popup
        var $container = $(this).closest('.popup');                

        // If no popup, default to body
        if (!$container.length) {
            $container = $(this.closest('.scroll-container, body'));
        } else {
            // Set popup to max height
            $container.height("90%");
        }

        // Determine if the table producing or increase scroll bar on the page...
        var widthWithTable = $container.width();
        var heightWithTable = $container.prop('scrollHeight');
        $(this).hide();

        var widthWithoutTable = $container.width();
        var heightWithoutTable = $container.prop('scrollHeight');
        $(this).show();

        var isCreatingScroll = widthWithTable != widthWithoutTable;
        var isIncreasingScroll = heightWithTable != heightWithoutTable;

        // Popup width does not change with scrollbars, assume table creates scroll bar.
        if ($container.is('.popup') || $container.is('.scroll-container')) {
            isCreatingScroll = true;
        }

        // Only setup scroll bars if necessary
        if (isIncreasingScroll) {
            var $tBody = $(this).find('tbody');

            // Set the column widths to a fixed amount.
            var widths = [];
            $tBody.find('tr').first().find('th, td').each(function () {
                widths.push($(this).width());
            });

            var multiColCells = [];

            // Set in batch to minimise reflow
            for (var i = 0; i < widths.length; i++) {
                // If any previous cell spans this column increase its width accordingly.
                for (var j = 0; j < multiColCells.length; j++) {
                    var item = multiColCells[j];

                    if (item.cols > 0) {
                        item.cell.css({ 'width': item.cell.width() + widths[i] });
                        item.cols--;
                    }
                }

                // Find cells starting in the current column.
                var $columnCells = $();
                $(this).find('tr').each(function() {
                    var col = 0;
                    var $rowCells = $(this).find('th, td');

                    // Loops the cells in the row (not necessarily a 1-to-1 correlation with the total columns)
                    for (var j = 0; j < $rowCells.length; j++) {
                        var $cell = $rowCells.eq(j);
                        var colSpan = $cell.attr('colspan');

                        // Does the cell start at the current column?
                        if (i == col) {
                            $columnCells = $columnCells.add($cell);
                        }

                        // Does the cell span multiple columns?
                        if (colSpan) {
                            colSpan = parseInt(colSpan);

                            if (colSpan > 1) {
                                if (i == col) {
                                    // Record so we can increase it later
                                    multiColCells.push({ cols: colSpan, cell: $cell });
                                }

                                // Skip relevant columns
                                col = col + colSpan;
                                continue;
                            }
                        }

                        // Move to next column
                        col++;
                    }
                });

                // Set the cells starting in this column to the columns width (multi-span columns will increase later)
                $columnCells.css({ 'width': widths[i] });
            }
            
            // Setup special CSS needed for scrolling
            $(this).css({ 'display': 'block' });
            $tBody.css({ 'display': 'block', 'overflow-y': 'scroll' });


            // Copy borders from bottom and right hand cells to produce clean design
            var $bottomRightCell = $tBody.find('tr').last().find('th, td').last();

            // Right border
            if ($(this).css('border-right-width') != 0) {
                // Copy border from cell to table body
                $tBody.css({ 'border-right': $bottomRightCell.css('border-right') });
            }

            // Bottom border
            if ($(this).css('border-bottom-width') != 0) {
                // Copy border from cell to table body
                $tBody.css({ 'border-bottom': $bottomRightCell.css('border-bottom') });

                // Remove the bottom border from the last cell to avoid a double up.
                $tBody.find('tr').last().find('th, td').css({ 'border-bottom-width': 0 });
            }

            // Calculate the scrollbar width
            var scrollWidth = $(this).width() - $tBody.find('tr').width();

            // Is the table the only element generating a scroll bar on the page?
            if (isCreatingScroll) {
                // The page scroll bar will disappear, so the page becomes wider.
                // That means the table header and footer should grow to compensate.

                // Add scrollbar width to the last column of the header and footer.
                $(this).find('thead, tfoot').find('tr').each(function () {            
                    var $lastCell = $(this).find('th, td').last();
                    $lastCell.width($lastCell.width() + scrollWidth);
                });
            } else {
                // The page scroll bar will not disappear, so the page remains the same size.
                // That means the table body should shrink to compensate for the extra scroll bar.

                // Subtract scrollbar width from the last column of the table body.
                $(this).find('tbody').find('tr').each(function () {
                    // First try to find a fluid cell.
                    var $lastCell = $(this).find('th.fluid, td.fluid').last();

                    // Otherwise use last cell
                    if (!$lastCell.length) {
                        $lastCell = $(this).find('th, td').last();
                    }

                    $lastCell.width($lastCell.width() - scrollWidth);
                });
            }

            // Increase padding on right aligned end cells to account for the scrollbar.
            $(this).find('thead, tfoot').find('tr').each(function () {            
                var $lastCell = $(this).find('th.right, td.right').last();

                if ($lastCell.length) {
                    $lastCell.append('<div class="scroll-spacer" style="float:right; width:' + scrollWidth + 'px; height:1px;"></div>')
                }
            });


            // Auto sized?
            if ($(this).hasClass('auto')) {
                // Start at zero
                $tBody.height(0);

                // Get natural height
                var scrollHeight = $container.prop('scrollHeight');

                // As a jumpstart, calculate closest match
                $tBody.height(scrollHeight - $tBody.offset().top); // Likely to be too tall initially.

                // For performance process with a halving algorithm
                var increment = 32;
                while (increment > 1) {
                    // Increase table height until page height increases
                    while (scrollHeight == $container.prop('scrollHeight')) {
                        $tBody.height($tBody.height() + increment);
                    }

                    // Halve the increment
                    increment = Math.round(increment / 2);

                    // Decrease table height until page height returns to normal
                    while (scrollHeight != $container.prop('scrollHeight')) {
                        $tBody.height($tBody.height() - increment);
                    }
                }
            }
        }

        // Return height to normal
        if ($container.is('.popup')) {
            $container.css({ 'height': 'auto' });
            centerVertically($container);
        }

        calculateStickies();
    });
}



/** @description Extracts text from an element.
 *  @param {HTMLElement} element An element from a web page.
 *  @returns {string} The text inside of an element.
 */
function getValueFromElement(element) {
    // Try and get the text value from inside the element excluding hidden content, scripts etc.
    var value = element.innerText;

    // If the element doesn't have a text value THEN try and get a value from an input field
    if (value.length == 0) {
        // Ignore buttons and hidden fields.
        value = $(element).find(':input:not(:button, :hidden)').val();
    }

    // Remove non numeric characters except for '.'
    if (value != undefined) {
        value = value.replace(/[^\d.-]/g, '');
    }

    return value;
}


/** @description Gets the sum of the numeric text stored in a series of elements.
 *  @param {JQuery} selector A JQuery selector that will be used to select the elements.
 *  @param {int} [precision] optional The precision that the total will be rounded to.
 *  @returns {Number} The Sum of the numeric text stored in a series of elements.
 */
function sumElements(selector, precision) {
    // Get all of the elements
    var $elements = $(selector);
    // Stores the sum of the elements.
    var total = 0;

    // If the precision is not defined THEN default to zero.
    if (precision == undefined) {
        precision = 0;
    }

    // Loop through each of the elements
    $elements.each(function () {
        // Get the floating point value of the elements text.
        var number = parseFloat(getValueFromElement(this));

        // Check if the number is a real number.
        if (!isNaN(number)) {
            // Add it to the total.
            total += number;
        }
        else {
            // If an element contains a value that is not a number THEN log error.
            throw new Error("An element contains a value that is not a number: '" + number + "'");

        }
    });
    // Return the sum of the elements to the precision that was requested.
    return parseFloat(total).toFixed(precision);
}

/** @description Multiplies the numeric text stored in a series of elements with the counterpart in another series of elements.
 *  @param {JQuery} selector A JQuery selector that will be used to select the elements.
 *  @param {int} [precision] optional The precision that the total will be rounded to.
 *  @returns {Number} Returns the total of the two sets of elements multiplied by each other to the precision that was requested.
 */
function multiplyElements(firstSelector, secondSelector, precision) {
    // Get all of the elements for the first selector.
    var $firstElements = $(firstSelector);

    // Get all of the elements for the second selector.
    var $secondElements = $(secondSelector);

    // Stores the total.
    var total = 0;

    // If the precision is not defined THEN default to zero.
    if (precision == undefined) {
        precision = 0;
    }

    // Both selectors must return an equal number of elements.
    if ($firstElements.length != $secondElements.length) {
        throw new Error('There must be an equal number of elements for both selectors.');
    }

    // Counter for the $secondElements array.
    var count = 0;

    // Loop through each of the elements
    $firstElements.each(function () {
        // Get the floating point value of the elements text.
        var firstNumber = parseFloat(getValueFromElement((this)));
        var secondNumber = parseFloat(getValueFromElement($secondElements[count]));
        // Check if the number is a real number.
        if (!isNaN(firstNumber) && !isNaN(secondNumber)) {
            // Multiply the two numbers and add it to the total.
            total += (firstNumber * secondNumber);
        }
        count++;
    });
    // Return the total of the two sets of elements multiplied by each other to the precision that was requested.
    return parseFloat(total).toFixed(precision);
}


/** @description Calculate the sum of a column in a table.
 *  @param {string} tableId The id of a table.
 *  @param {string} columnClass The class of a table header that will be summed.
 *  @param {int} [precision] optional The precision that the total will be rounded to.
 *  @returns {Number} The Sum of the numeric text stored in a table column.
 */
function sumTableColumn(tableId, columnClass, precision) {
    // Get the header for the cost column
    var $header = $('#' + tableId + ' th.' + columnClass);

    // If the precision is not defined THEN default to zero.
    if (precision == undefined) {
        precision = 0;
    }

    // Check to see if the cost header exists.
    if ($header.length == 0) {
        // If the column is missing THEN we should ask the developers to fix it.
        throw new Error("The column '" + columnClass + "' could not be found");
    }
    else {
        // Get the column index for the header.
        // The index is zero indexed so we need to add one.
        var index = $header.index() + 1;

        // Get the total for all of the cells that are in the column.
        var total = sumElements('#' + tableId + ' tbody td:nth-child(' + index + ')', precision);

        // Set the total in the footer to the new total value.
        return total;
    }
}

/** @description Multiplies two columns together.
 *  @param {string} tableId The id of a table.
 *  @param {string} firstColumnClass The class of the first table header that will be multiplied.
 *  @param {string} secondColumnClass The class of the second table header that will be multiplied.
 *  @param {int} [precision] optional The precision that the total will be rounded to.
 *  @returns {Number} The value of the two columns multiplied by each other.
 */
function multiplyTableColumns(tableId, firstColumnClass, secondColumnClass, precision) {
    // Get the header for the cost column
    var $firstHeader = $('#' + tableId + ' th.' + firstColumnClass);

    var $secondHeader = $('#' + tableId + ' th.' + secondColumnClass);


    // If the precision is not defined THEN default to zero.
    if (precision == undefined) {
        precision = 0;
    }

    // Check to see if the first header exists.
    if ($firstHeader.length == 0) {
        // If the column is missing THEN we should ask the developers to fix it.
        throw new Error("The column '" + firstColumnClass + "' could not be found");
    }

    // Check to see if the second header exists.
    if ($firstHeader.length == 0) {
        // If the column is missing THEN we should ask the developers to fix it.
        throw new Error("The column '" + secondColumnClass + "' could not be found");
    }
    else {
        // Get the column index for the first header.
        // The index is zero indexed so we need to add one.
        var firstIndex = $firstHeader.index() + 1;

        // Get the column index for the second header.
        // The index is zero indexed so we need to add one.
        var secondIndex = $secondHeader.index() + 1;

        // The selectors for multiplyElements.
        var firstSelector = '#' + tableId + ' tbody td:nth-child(' + firstIndex + ')';
        var secondSelector = '#' + tableId + ' tbody td:nth-child(' + secondIndex + ')';

        // Get the total for all of the cells that are in the column.
        var total = multiplyElements(firstSelector, secondSelector, precision);

        // Set the total in the footer to the new total value.
        return total;
    }
};
// Activate extended functionality on all kendo tab controls on the page.
function setupTabs() {
    setupTab($(".k-tabstrip"));
}

// Extends functionality of the given kendo tab control.
function setupTab($tab) {
    $tab.each(function () {
        var $tabStrip = $(this);
        var $tabs = $tabStrip.children(".k-tabstrip-items").find(".k-item");
        var tabCookie = "Current_Tab_" + $tabStrip.attr("id");

        // Tab change
        $tabs.click(function () {
            // Remember kendo tab
            createCookie(tabCookie, $(this).attr("aria-controls"), 1);

            // If tab has checkbox, check it
            $input = $(this).find('input').prop("checked", true);
            if ($input) {
                $('input[name="' + $input.attr('name') + '"]').change();
            }
        });

        // preventDefault bug fix.
        $tabs.find("input").click(function (e) {
            e.stopPropagation();
            $(this).parent().click();
        });


        // If cookie set, select tab - Please do not disable this functionality without discussion.
        var tab = readCookie(tabCookie);
        
        // Check if the tabstrip tracks changes - For case by case instances, js-forgetful will ensure a specific set of tabs do not remember their state between page loads.
        if ($tabStrip.hasClass('js-forgetful')) {
            tab = null;
        }

        // If any errors are shown, select first tab with an error message.
        var errorTab = findErrorTab($tabStrip);
        if (errorTab) {
            tab = errorTab;
        }

        // Detect tab to select from parameter passed by query string.
        var tabStripId = $tabStrip.attr('id');
        if (tabStripId) {
            var queryString = getParameterByName(tabStripId);

            if (queryString) {
                tab = queryString;
            }
        }

        selectTab($tabStrip, tab);
    });
}

/** @description Finds the first tab with a validation error present.
 */
function findErrorTab($tabStrip) {
    var $errors = $tabStrip.find('.field-validation-error');
    if ($errors.length) {
        // Get all error message parent tab containers
        var $errorContainer = $errors.parents('.k-content').first();
        var $tabContainers = $tabStrip.find('.k-content');
        var result;

        var i = -1;
        $tabContainers.each(function () {
            i++;
            if ($tabContainers[i] === $errorContainer[0]) {
                var $tabs = $tabStrip.find(".k-tabstrip-items .k-item");

                result = $tabs.eq(i).attr('aria-controls');
            }
        });

        return result;
    }
}


/** @description Trigger display of a tab using the given identifier (aria or HTML ID).
 */
function selectTab($tabStrip, tab) {
    if (tab) {
        var $tabs = $tabStrip.find(".k-tabstrip-items .k-item");
        $tabs.each(function () {
            if ($(this).attr("aria-controls") == tab || $(this).attr("id") == tab) {
                $(this).click();
            }
        });
    }
};


/**@decription Determines if the browser supports the File API needed for Javascript based uploads.
 */
function hasFileAPI() {
    return window.File && window.FileList;
}


/**@description Generates a hidden form used to upload files.
 * @param {string} postUrl URL the file is uploaded to.
 * @param {object} [additionalData] Optional: An Associative Array. Keys become field names used to submit the linked values.
 */
function buildHiddenUploadForm(postUrl, additionalData) {
    var $form = $('<form action="' + postUrl + '" method="post" enctype="multipart/form-data" style="display:none"></form>');

    if (additionalData) {
        // Loop key value pairs
        for (var key in additionalData) {
            // Create hidden fields for the additional data
            var $hidden = $('<input name="' + key + '" type="hidden" />');
            $form.append($hidden);
            $hidden.val(additionalData[key]);
        }
    }
    
    $('body').append($form);
    return $form;
}


/**@description Displays the standard file selection dialog then instantly posts the selection file(s) back to the server.
 * @param {string} postUrl URL the file is uploaded to.
 * @param {string} fieldName Form prefix and member name given to the upload.
 * @param {bool} [isAjax] Optional: Determines if the postback is asynchronous.
 * @param {callback} [ajaxCallback] Optional: Function called once the upload is complete. Server response is passed as the first parameter.
 * @param {bool} [allowMultiple] Optional: Determines if the file selection dialog allows selection of multiple files.
 * @param {object} [additionalData] Optional: An Associative Array. Keys become field names used to submit the linked values.
 */
function openFileDialog(postUrl, fieldName, isAjax, ajaxCallback, allowMultiple, additionalData) {
    // Build invisible form.
    var $form = buildHiddenUploadForm(postUrl, additionalData);
    var $upload = $('<input name="' + fieldName + '" type="file" />');

    if (allowMultiple) { $upload.attr('mulitple', true); }

    $form.append($upload);

    // Tigger submission on file selection.
    $upload.change(function() {
        $form.submit();
    });

    // Tack on custom functionality to form submission
    $form.submit(function(e) {
        // Post synchronously
        if (!isAjax) { return true; }

        // Post asynchronously
        e.preventDefault();
        showLoadingAnimation();

        $.ajax($form.attr('action'),
            {
                cache: false,
                type: 'POST',
                data: new FormData($form[0]),
                processData: false,
                contentType: false
            })
            .done(function (response) {
                $form.remove();
                hideLoadingAnimation();

                if (ajaxCallback) {
                    ajaxCallback(response);
                } else {
                    // Show error?
                    if (response.IsSuccess) {
                        showSuccessMessage("File uploaded.");
                    } else {
                        showErrorMessage(response.Message, "Upload Error");
                    }
                }
            })
            .fail(handleAjaxError);

        return false;
    });

    // Tigger upload dialog
    $upload.click();
}


/**@description Enables instant drag 'n' drop uploads.
 * @param {string} postUrl URL the file(s) is uploaded to.
 * @param {string} fieldName Form prefix and member name given to the upload.
 * @param {callback} [ajaxCallback] Optional: Function called once the upload is complete. Server response is passed as the first parameter.
 * @param {bool} [allowMultiple] Optional: Determines if the file selection dialog allows selection of multiple files.
 * @param {object} [additionalData] Optional: An Associative Array. Keys become field names used to submit the linked values.
 */
function setupUploadDropZone($dropZone, postUrl, fieldName, ajaxCallback, allowMultiple, additionalData) {
    // Browser support?
    if (!hasFileAPI()) { return; }

    $dropZone.addClass('drop-zone');

    // Timer used to remove hover state to prevent 'flickering'.
    var timer;
    
    // Setup drag and drop events
    $dropZone.on('drag dragend dragenter dragleave dragover dragstart drop', function (e) {
        e.preventDefault();

        // Reset timeout eveytime a new event occurs
        clearTimeout(timer);

        // Hover?
        if (e.type === "dragenter" || e.type === "dragover") {
            // Already in hover state?
            if (!$dropZone.hasClass("drag-hover")) {
                // Clear hover state on all other drop zones
                $('.drag-hover').removeClass("drag-hover");

                // Add hover state styling
                $dropZone.addClass("drag-hover");
            }
        } else {
            // Unhover - Delay by 100ms to prevent flickering
            timer = setTimeout(function () {
                $dropZone.removeClass("drag-hover");
            }, 100);
        }


        // Get files dropped onto the drop zone
        var files;
        if (e.type === "drop" && e.originalEvent.dataTransfer) {
            files = e.originalEvent.dataTransfer.files;
        }

        if (!files || !files.length) {
            return;
        }        

        // Prepare files for upload
        $dropZone.addClass("uploading");

        var $form = buildHiddenUploadForm(postUrl, additionalData);        
        var data = new FormData($form[0]);
        
        for (var i = 0; i < files.length; i++) {
            data.append(fieldName, files[i]);
        }

        // Upload
        showLoadingAnimation();
        $.ajax($form.attr('action'),
            {
                cache: false,
                type: 'POST',
                data: data,
                processData: false,
                contentType: false
            })
            .done(function (response) {
                $dropZone.removeClass("uploading");
                $form.remove();
                hideLoadingAnimation();

                if (ajaxCallback) {
                    ajaxCallback(response);
                } else {
                    // Show error?
                    if (response.IsSuccess) {
                        showSuccessMessage("File uploaded.");
                    } else {
                        showErrorMessage(response.Message, "Upload Error");
                    }
                }
            })
            .fail(handleAjaxError);
    });
};
/*
 * 
 * TableSorter 2.0 - Client-side table sorting with ease!
 * Version 2.0.5b
 * @requires jQuery v1.2.3
 * 
 * Copyright (c) 2007 Christian Bach
 * Examples and docs at: http://tablesorter.com
 * Dual licensed under the MIT and GPL licenses:
 * http://www.opensource.org/licenses/mit-license.php
 * http://www.gnu.org/licenses/gpl.html
 * 
 */
/**
 * 
 * @description Create a sortable table with multi-column sorting capabilitys
 * 
 * @example $('table').tablesorter();
 * @desc Create a simple tablesorter interface.
 * 
 * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] });
 * @desc Create a tablesorter interface and sort on the first and secound column column headers.
 * 
 * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } });
 *          
 * @desc Create a tablesorter interface and disableing the first and second  column headers.
 *      
 * 
 * @example $('table').tablesorter({ headers: { 0: {sorter:"integer"}, 1: {sorter:"currency"} } });
 * 
 * @desc Create a tablesorter interface and set a column parser for the first
 *       and second column.
 * 
 * 
 * @param Object
 *            settings An object literal containing key/value pairs to provide
 *            optional settings.
 * 
 * 
 * @option String cssHeader (optional) A string of the class name to be appended
 *         to sortable tr elements in the thead of the table. Default value:
 *         "header"
 * 
 * @option String cssAsc (optional) A string of the class name to be appended to
 *         sortable tr elements in the thead on a ascending sort. Default value:
 *         "headerSortUp"
 * 
 * @option String cssDesc (optional) A string of the class name to be appended
 *         to sortable tr elements in the thead on a descending sort. Default
 *         value: "headerSortDown"
 * 
 * @option String sortInitialOrder (optional) A string of the inital sorting
 *         order can be asc or desc. Default value: "asc"
 * 
 * @option String sortMultisortKey (optional) A string of the multi-column sort
 *         key. Default value: "shiftKey"
 * 
 * @option String textExtraction (optional) A string of the text-extraction
 *         method to use. For complex html structures inside td cell set this
 *         option to "complex", on large tables the complex option can be slow.
 *         Default value: "simple"
 * 
 * @option Object headers (optional) An array containing the forces sorting
 *         rules. This option let's you specify a default sorting rule. Default
 *         value: null
 * 
 * @option Array sortList (optional) An array containing the forces sorting
 *         rules. This option let's you specify a default sorting rule. Default
 *         value: null
 * 
 * @option Array sortForce (optional) An array containing forced sorting rules.
 *         This option let's you specify a default sorting rule, which is
 *         prepended to user-selected rules. Default value: null
 * 
 * @option Boolean sortLocaleCompare (optional) Boolean flag indicating whatever
 *         to use String.localeCampare method or not. Default set to true.
 * 
 * 
 * @option Array sortAppend (optional) An array containing forced sorting rules.
 *         This option let's you specify a default sorting rule, which is
 *         appended to user-selected rules. Default value: null
 * 
 * @option Boolean widthFixed (optional) Boolean flag indicating if tablesorter
 *         should apply fixed widths to the table columns. This is usefull when
 *         using the pager companion plugin. This options requires the dimension
 *         jquery plugin. Default value: false
 * 
 * @option Boolean cancelSelection (optional) Boolean flag indicating if
 *         tablesorter should cancel selection of the table headers text.
 *         Default value: true
 * 
 * @option Boolean debug (optional) Boolean flag indicating if tablesorter
 *         should display debuging information usefull for development.
 * 
 * @type jQuery
 * 
 * @name tablesorter
 * 
 * @cat Plugins/Tablesorter
 * 
 * @author Christian Bach/christian.bach@polyester.se
 */

(function ($) {
    $.extend({
        tablesorter: new
        function () {

            var parsers = [],
                widgets = [];

            this.defaults = {
                cssHeader: "header",
                cssAsc: "headerSortUp",
                cssDesc: "headerSortDown",
                cssChildRow: "expand-child",
                sortInitialOrder: "asc",
                sortMultiSortKey: "shiftKey",
                sortForce: null,
                sortAppend: null,
                sortLocaleCompare: true,
                textExtraction: "simple",
                parsers: {}, widgets: [],
                widgetZebra: {
                    css: ["even", "odd"]
                }, headers: {}, widthFixed: false,
                cancelSelection: true,
                sortList: [],
                headerList: [],
                dateFormat: "us",
                decimal: '/\.|\,/g',
                onRenderHeader: null,
                selectorHeaders: 'thead th',
                debug: false
            };

            /* debuging utils */

            function benchmark(s, d) {
                log(s + "," + (new Date().getTime() - d.getTime()) + "ms");
            }

            this.benchmark = benchmark;

            function log(s) {
                if (typeof console != "undefined" && typeof console.debug != "undefined") {
                    console.log(s);
                } else {
                    alert(s);
                }
            }

            /* parsers utils */

            function buildParserCache(table, $headers) {

                if (table.config.debug) {
                    var parsersDebug = "";
                }

                if (table.tBodies.length == 0) return; // In the case of empty tables
                var rows = table.tBodies[0].rows;

                if (rows[0]) {

                    var list = [],
                        cells = rows[0].cells,
                        l = cells.length;

                    for (var i = 0; i < l; i++) {

                        var p = false;

                        if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) {

                            p = getParserById($($headers[i]).metadata().sorter);

                        } else if ((table.config.headers[i] && table.config.headers[i].sorter)) {

                            p = getParserById(table.config.headers[i].sorter);
                        }
                        if (!p) {

                            p = detectParserForColumn(table, rows, -1, i);
                        }

                        if (table.config.debug) {
                            parsersDebug += "column:" + i + " parser:" + p.id + "\n";
                        }

                        list.push(p);
                    }
                }

                if (table.config.debug) {
                    log(parsersDebug);
                }

                return list;
            };

            function detectParserForColumn(table, rows, rowIndex, cellIndex) {
                var l = parsers.length,
                    node = false,
                    nodeValue = false,
                    keepLooking = true;
                while (nodeValue == '' && keepLooking) {
                    rowIndex++;
                    if (rows[rowIndex]) {
                        node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex);
                        nodeValue = trimAndGetNodeText(table.config, node);
                        if (table.config.debug) {
                            log('Checking if value was empty on row:' + rowIndex);
                        }
                    } else {
                        keepLooking = false;
                    }
                }
                for (var i = 1; i < l; i++) {
                    if (parsers[i].is(nodeValue, table, node)) {
                        return parsers[i];
                    }
                }
                // 0 is always the generic parser (text)
                return parsers[0];
            }

            function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) {
                return rows[rowIndex].cells[cellIndex];
            }

            function trimAndGetNodeText(config, node) {
                return $.trim(getElementText(config, node));
            }

            function getParserById(name) {
                var l = parsers.length;
                for (var i = 0; i < l; i++) {
                    if (parsers[i].id.toLowerCase() == name.toLowerCase()) {
                        return parsers[i];
                    }
                }
                return false;
            }

            /* utils */

            function buildCache(table) {

                if (table.config.debug) {
                    var cacheTime = new Date();
                }

                var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0,
                    totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0,
                    parsers = table.config.parsers,
                    cache = {
                        row: [],
                        normalized: []
                    };

                for (var i = 0; i < totalRows; ++i) {

                    /** Add the table data to main data array */
                    var c = $(table.tBodies[0].rows[i]),
                        cols = [];

                    // if this is a child row, add it to the last row's children and
                    // continue to the next row
                    if (c.hasClass(table.config.cssChildRow)) {
                        cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c);
                        // go to the next for loop
                        continue;
                    }

                    cache.row.push(c);

                    for (var j = 0; j < totalCells; ++j) {
                        cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j]));
                    }

                    cols.push(cache.normalized.length); // add position for rowCache
                    cache.normalized.push(cols);
                    cols = null;
                };

                if (table.config.debug) {
                    benchmark("Building cache for " + totalRows + " rows:", cacheTime);
                }

                return cache;
            };

            function getElementText(config, node) {

                var text = "";

                if (!node) return "";

                if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false;

                if (config.textExtraction == "simple") {
                    if (config.supportsTextContent) {
                        text = node.textContent;
                    } else {
                        if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) {
                            text = node.childNodes[0].innerHTML;
                        } else {
                            text = node.innerHTML;
                        }
                    }
                } else {
                    if (typeof(config.textExtraction) == "function") {
                        text = config.textExtraction(node);
                    } else {
                        text = $(node).text();
                    }
                }
                return text;
            }

            function appendToTable(table, cache) {

                if (table.config.debug) {
                    var appendTime = new Date()
                }

                var c = cache,
                    r = c.row,
                    n = c.normalized,
                    totalRows = n.length,
                    checkCell = (n[0].length - 1),
                    tableBody = $(table.tBodies[0]),
                    rows = [];


                for (var i = 0; i < totalRows; i++) {
                    var pos = n[i][checkCell];

                    rows.push(r[pos]);

                    if (!table.config.appender) {

                        //var o = ;
                        var l = r[pos].length;
                        for (var j = 0; j < l; j++) {
                            tableBody[0].appendChild(r[pos][j]);
                        }

                        // 
                    }
                }



                if (table.config.appender) {

                    table.config.appender(table, rows);
                }

                rows = null;

                if (table.config.debug) {
                    benchmark("Rebuilt table:", appendTime);
                }

                // apply table widgets
                applyWidget(table);

                // trigger sortend
                setTimeout(function () {
                    $(table).trigger("sortEnd");
                }, 0);

            };

            function buildHeaders(table) {

                if (table.config.debug) {
                    var time = new Date();
                }

                var meta = ($.metadata) ? true : false;
                
                var header_index = computeTableHeaderCellIndexes(table);

                $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) {

                    this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex];
                    // this.column = index;
                    this.order = formatSortingOrder(table.config.sortInitialOrder);
                    
					
					this.count = this.order;

                    if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true;
					if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index);

                    if (!this.sortDisabled) {
                        var $th = $(this).addClass(table.config.cssHeader);
                        if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th);
                    }

                    // add cell to headerList
                    table.config.headerList[index] = this;
                });

                if (table.config.debug) {
                    benchmark("Built headers:", time);
                    log($tableHeaders);
                }

                return $tableHeaders;

            };

            // from:
            // http://www.javascripttoolbox.com/lib/table/examples.php
            // http://www.javascripttoolbox.com/temp/table_cellindex.html


            function computeTableHeaderCellIndexes(t) {
                var matrix = [];
                var lookup = {};
                var thead = t.getElementsByTagName('THEAD')[0];
                var trs = thead.getElementsByTagName('TR');

                for (var i = 0; i < trs.length; i++) {
                    var cells = trs[i].cells;
                    for (var j = 0; j < cells.length; j++) {
                        var c = cells[j];

                        var rowIndex = c.parentNode.rowIndex;
                        var cellId = rowIndex + "-" + c.cellIndex;
                        var rowSpan = c.rowSpan || 1;
                        var colSpan = c.colSpan || 1
                        var firstAvailCol;
                        if (typeof(matrix[rowIndex]) == "undefined") {
                            matrix[rowIndex] = [];
                        }
                        // Find first available column in the first row
                        for (var k = 0; k < matrix[rowIndex].length + 1; k++) {
                            if (typeof(matrix[rowIndex][k]) == "undefined") {
                                firstAvailCol = k;
                                break;
                            }
                        }
                        lookup[cellId] = firstAvailCol;
                        for (var k = rowIndex; k < rowIndex + rowSpan; k++) {
                            if (typeof(matrix[k]) == "undefined") {
                                matrix[k] = [];
                            }
                            var matrixrow = matrix[k];
                            for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) {
                                matrixrow[l] = "x";
                            }
                        }
                    }
                }
                return lookup;
            }

            function checkCellColSpan(table, rows, row) {
                var arr = [],
                    r = table.tHead.rows,
                    c = r[row].cells;

                for (var i = 0; i < c.length; i++) {
                    var cell = c[i];

                    if (cell.colSpan > 1) {
                        arr = arr.concat(checkCellColSpan(table, headerArr, row++));
                    } else {
                        if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) {
                            arr.push(cell);
                        }
                        // headerArr[row] = (i+row);
                    }
                }
                return arr;
            };

            function checkHeaderMetadata(cell) {
                if (($.metadata) && ($(cell).metadata().sorter === false)) {
                    return true;
                };
                return false;
            }

            function checkHeaderOptions(table, i) {
                if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) {
                    return true;
                };
                return false;
            }
			
			 function checkHeaderOptionsSortingLocked(table, i) {
                if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder;
                return false;
            }
			
            function applyWidget(table) {
                var c = table.config.widgets;
                var l = c.length;
                for (var i = 0; i < l; i++) {

                    getWidgetById(c[i]).format(table);
                }

            }

            function getWidgetById(name) {
                var l = widgets.length;
                for (var i = 0; i < l; i++) {
                    if (widgets[i].id.toLowerCase() == name.toLowerCase()) {
                        return widgets[i];
                    }
                }
            };

            function formatSortingOrder(v) {
                if (typeof(v) != "Number") {
                    return (v.toLowerCase() == "desc") ? 1 : 0;
                } else {
                    return (v == 1) ? 1 : 0;
                }
            }

            function isValueInArray(v, a) {
                var l = a.length;
                for (var i = 0; i < l; i++) {
                    if (a[i][0] == v) {
                        return true;
                    }
                }
                return false;
            }

            function setHeadersCss(table, $headers, list, css) {
                // remove all header information
                $headers.removeClass(css[0]).removeClass(css[1]);

                var h = [];
                $headers.each(function (offset) {
                    if (!this.sortDisabled) {
                        h[this.column] = $(this);
                    }
                });

                var l = list.length;
                for (var i = 0; i < l; i++) {
                    h[list[i][0]].addClass(css[list[i][1]]);
                }
            }

            function fixColumnWidth(table, $headers) {
                var c = table.config;
                if (c.widthFixed) {
                    var colgroup = $('<colgroup>');
                    $("tr:first td", table.tBodies[0]).each(function () {
                        colgroup.append($('<col>').css('width', $(this).width()));
                    });
                    $(table).prepend(colgroup);
                };
            }

            function updateHeaderSortCount(table, sortList) {
                var c = table.config,
                    l = sortList.length;
                for (var i = 0; i < l; i++) {
                    var s = sortList[i],
                        o = c.headerList[s[0]];
                    o.count = s[1];
                    o.count++;
                }
            }

            /* sorting methods */

            function multisort(table, sortList, cache) {

                if (table.config.debug) {
                    var sortTime = new Date();
                }

                var dynamicExp = "var sortWrapper = function(a,b) {",
                    l = sortList.length;

                // TODO: inline functions.
                for (var i = 0; i < l; i++) {

                    var c = sortList[i][0];
                    var order = sortList[i][1];
                    // var s = (getCachedSortType(table.config.parsers,c) == "text") ?
                    // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ?
                    // "sortNumeric" : "sortNumericDesc");
                    // var s = (table.config.parsers[c].type == "text") ? ((order == 0)
                    // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ?
                    // makeSortNumeric(c) : makeSortNumericDesc(c));
                    var s = (table.config.parsers[c].type == "text") ? ((order == 0) ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c)) : ((order == 0) ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c));
                    var e = "e" + i;

                    dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c
                    // + "]); ";
                    dynamicExp += "if(" + e + ") { return " + e + "; } ";
                    dynamicExp += "else { ";

                }

                // if value is the same keep orignal order
                var orgOrderCol = cache.normalized[0].length - 1;
                dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];";

                for (var i = 0; i < l; i++) {
                    dynamicExp += "}; ";
                }

                dynamicExp += "return 0; ";
                dynamicExp += "}; ";

                if (table.config.debug) {
                    benchmark("Evaling expression:" + dynamicExp, new Date());
                }

                eval(dynamicExp);

                cache.normalized.sort(sortWrapper);

                if (table.config.debug) {
                    benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime);
                }

                return cache;
            };

            function makeSortFunction(type, direction, index) {
                var a = "a[" + index + "]",
                    b = "b[" + index + "]";
                if (type == 'text' && direction == 'asc') {
                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));";
                } else if (type == 'text' && direction == 'desc') {
                    return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));";
                } else if (type == 'numeric' && direction == 'asc') {
                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));";
                } else if (type == 'numeric' && direction == 'desc') {
                    return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));";
                }
            };

            function makeSortText(i) {
                return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));";
            };

            function makeSortTextDesc(i) {
                return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));";
            };

            function makeSortNumeric(i) {
                return "a[" + i + "]-b[" + i + "];";
            };

            function makeSortNumericDesc(i) {
                return "b[" + i + "]-a[" + i + "];";
            };

            function sortText(a, b) {
                if (table.config.sortLocaleCompare) return a.localeCompare(b);
                return ((a < b) ? -1 : ((a > b) ? 1 : 0));
            };

            function sortTextDesc(a, b) {
                if (table.config.sortLocaleCompare) return b.localeCompare(a);
                return ((b < a) ? -1 : ((b > a) ? 1 : 0));
            };

            function sortNumeric(a, b) {
                return a - b;
            };

            function sortNumericDesc(a, b) {
                return b - a;
            };

            function getCachedSortType(parsers, i) {
                return parsers[i].type;
            }; /* public methods */
            this.construct = function (settings) {
                return this.each(function () {
                    // if no thead or tbody quit.
                    if (!this.tHead || !this.tBodies) return;
                    // declare
                    var $this, $document, $headers, cache, config, shiftDown = 0,
                        sortOrder;
                    // new blank config object
                    this.config = {};
                    // merge and extend.
                    config = $.extend(this.config, $.tablesorter.defaults, settings);
                    // store common expression for speed
                    $this = $(this);
                    // save the settings where they read
                    $.data(this, "tablesorter", config);
                    // build headers
                    $headers = buildHeaders(this);
                    // try to auto detect column type, and store in tables config
                    this.config.parsers = buildParserCache(this, $headers);
                    // build the cache for the tbody cells
                    cache = buildCache(this);
                    // get the css class names, could be done else where.
                    var sortCSS = [config.cssDesc, config.cssAsc];
                    // fixate columns if the users supplies the fixedWidth option
                    fixColumnWidth(this);
                    // apply event handling to headers
                    // this is to big, perhaps break it out?
                    $headers.click(

                    function (e) {
                        var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0;
                        if (!this.sortDisabled && totalRows > 0) {
                            // Only call sortStart if sorting is
                            // enabled.
                            $this.trigger("sortStart");
                            // store exp, for speed
                            var $cell = $(this);
                            // get current column index
                            var i = this.column;
                            // get current column sort order
                            this.order = this.count++ % 2;
							// always sort on the locked order.
							if(this.lockedOrder) this.order = this.lockedOrder;
							
							// user only whants to sort on one
                            // column
                            if (!e[config.sortMultiSortKey]) {
                                // flush the sort list
                                config.sortList = [];
                                if (config.sortForce != null) {
                                    var a = config.sortForce;
                                    for (var j = 0; j < a.length; j++) {
                                        if (a[j][0] != i) {
                                            config.sortList.push(a[j]);
                                        }
                                    }
                                }
                                // add column to sort list
                                config.sortList.push([i, this.order]);
                                // multi column sorting
                            } else {
                                // the user has clicked on an all
                                // ready sortet column.
                                if (isValueInArray(i, config.sortList)) {
                                    // revers the sorting direction
                                    // for all tables.
                                    for (var j = 0; j < config.sortList.length; j++) {
                                        var s = config.sortList[j],
                                            o = config.headerList[s[0]];
                                        if (s[0] == i) {
                                            o.count = s[1];
                                            o.count++;
                                            s[1] = o.count % 2;
                                        }
                                    }
                                } else {
                                    // add column to sort list array
                                    config.sortList.push([i, this.order]);
                                }
                            };
                            setTimeout(function () {
                                // set css for headers
                                setHeadersCss($this[0], $headers, config.sortList, sortCSS);
                                appendToTable(
	                                $this[0], multisort(
	                                $this[0], config.sortList, cache)
								);
                            }, 1);
                            // stop normal event by returning false
                            return false;
                        }
                        // cancel selection
                    }).mousedown(function () {
                        if (config.cancelSelection) {
                            this.onselectstart = function () {
                                return false
                            };
                            return false;
                        }
                    });
                    // apply easy methods that trigger binded events
                    $this.bind("update", function () {
                        var me = this;
                        setTimeout(function () {
                            // rebuild parsers.
                            me.config.parsers = buildParserCache(
                            me, $headers);
                            // rebuild the cache map
                            cache = buildCache(me);
                        }, 1);
                    }).bind("updateCell", function (e, cell) {
                        var config = this.config;
                        // get position from the dom.
                        var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex];
                        // update cache
                        cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format(
                        getElementText(config, cell), cell);
                    }).bind("sorton", function (e, list) {
                        $(this).trigger("sortStart");
                        config.sortList = list;
                        // update and store the sortlist
                        var sortList = config.sortList;
                        // update header count index
                        updateHeaderSortCount(this, sortList);
                        // set css for headers
                        setHeadersCss(this, $headers, sortList, sortCSS);
                        // sort the table and append it to the dom
                        appendToTable(this, multisort(this, sortList, cache));
                    }).bind("appendCache", function () {
                        appendToTable(this, cache);
                    }).bind("applyWidgetId", function (e, id) {
                        getWidgetById(id).format(this);
                    }).bind("applyWidgets", function () {
                        // apply widgets
                        applyWidget(this);
                    });
                    if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) {
                        config.sortList = $(this).metadata().sortlist;
                    }
                    // if user has supplied a sort list to constructor.
                    if (config.sortList.length > 0) {
                        $this.trigger("sorton", [config.sortList]);
                    }
                    // apply widgets
                    applyWidget(this);
                });
            };
            this.addParser = function (parser) {
                var l = parsers.length,
                    a = true;
                for (var i = 0; i < l; i++) {
                    if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) {
                        a = false;
                    }
                }
                if (a) {
                    parsers.push(parser);
                };
            };
            this.addWidget = function (widget) {
                widgets.push(widget);
            };
            this.formatFloat = function (s) {
                var i = parseFloat(s);
                return (isNaN(i)) ? 0 : i;
            };
            this.formatInt = function (s) {
                var i = parseInt(s);
                return (isNaN(i)) ? 0 : i;
            };
            this.isDigit = function (s, config) {
                // replace all an wanted chars and match.
                return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, '')));
            };
            this.clearTableBody = function (table) {
                if ($.browser.msie) {
                    function empty() {
                        while (this.firstChild)
                        this.removeChild(this.firstChild);
                    }
                    empty.apply(table.tBodies[0]);
                } else {
                    table.tBodies[0].innerHTML = "";
                }
            };
        }
    });

    // extend plugin scope
    $.fn.extend({
        tablesorter: $.tablesorter.construct
    });

    // make shortcut
    var ts = $.tablesorter;

    // add default parsers
    ts.addParser({
        id: "text",
        is: function (s) {
            return true;
        }, format: function (s) {
            return $.trim(s.toLocaleLowerCase());
        }, type: "text"
    });

    ts.addParser({
        id: "digit",
        is: function (s, table) {
            var c = table.config;
            return $.tablesorter.isDigit(s, c);
        }, format: function (s) {
            return $.tablesorter.formatFloat(s);
        }, type: "numeric"
    });

    ts.addParser({
        id: "currency",
        is: function (s) {
            return /^[£$€?.]/.test(s);
        }, format: function (s) {
            return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), ""));
        }, type: "numeric"
    });

    ts.addParser({
        id: "ipAddress",
        is: function (s) {
            return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);
        }, format: function (s) {
            var a = s.split("."),
                r = "",
                l = a.length;
            for (var i = 0; i < l; i++) {
                var item = a[i];
                if (item.length == 2) {
                    r += "0" + item;
                } else {
                    r += item;
                }
            }
            return $.tablesorter.formatFloat(r);
        }, type: "numeric"
    });

    ts.addParser({
        id: "url",
        is: function (s) {
            return /^(https?|ftp|file):\/\/$/.test(s);
        }, format: function (s) {
            return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), ''));
        }, type: "text"
    });

    ts.addParser({
        id: "isoDate",
        is: function (s) {
            return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);
        }, format: function (s) {
            return $.tablesorter.formatFloat((s != "") ? new Date(s.replace(
            new RegExp(/-/g), "/")).getTime() : "0");
        }, type: "numeric"
    });

    ts.addParser({
        id: "percent",
        is: function (s) {
            return /\%$/.test($.trim(s));
        }, format: function (s) {
            return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), ""));
        }, type: "numeric"
    });

    ts.addParser({
        id: "usLongDate",
        is: function (s) {
            return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));
        }, format: function (s) {
            return $.tablesorter.formatFloat(new Date(s).getTime());
        }, type: "numeric"
    });

    ts.addParser({
        id: "shortDate",
        is: function (s) {
            return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);
        }, format: function (s, table) {
            var c = table.config;
            s = s.replace(/\-/g, "/");
            if (c.dateFormat == "us") {
                // reformat the string in ISO format
                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2");
            } else if (c.dateFormat == "uk") {
                // reformat the string in ISO format
                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1");
            } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") {
                s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3");
            }
            return $.tablesorter.formatFloat(new Date(s).getTime());
        }, type: "numeric"
    });
    ts.addParser({
        id: "time",
        is: function (s) {
            return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);
        }, format: function (s) {
            return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime());
        }, type: "numeric"
    });
    ts.addParser({
        id: "metadata",
        is: function (s) {
            return false;
        }, format: function (s, table, cell) {
            var c = table.config,
                p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName;
            return $(cell).metadata()[p];
        }, type: "numeric"
    });
    // add default widgets
    ts.addWidget({
        id: "zebra",
        format: function (table) {
            if (table.config.debug) {
                var time = new Date();
            }
            var $tr, row = -1,
                odd;
            // loop through the visible rows
            $("tr:visible", table.tBodies[0]).each(function (i) {
                $tr = $(this);
                // style children rows the same way the parent
                // row was styled
                if (!$tr.hasClass(table.config.cssChildRow)) row++;
                odd = (row % 2 == 0);
                $tr.removeClass(
                table.config.widgetZebra.css[odd ? 0 : 1]).addClass(
                table.config.widgetZebra.css[odd ? 1 : 0])
            });
            if (table.config.debug) {
                $.tablesorter.benchmark("Applying Zebra widget", time);
            }
        }
    });
})(jQuery);;
/** 
 * Kendo UI v2017.2.621 (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.621'.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 = autosize ? outerWidth(element) + 1 : 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: autosize ? outerWidth(element) + 1 : 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 - 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)) {
                    var hasChildrenObject = hasChildren.call(that, that);
                    if (hasChildrenObject && hasChildrenObject.length === 0) {
                        that.hasChildren = false;
                    } else {
                        that.hasChildren = !!hasChildrenObject;
                    }
                }
                that._childrenOptions = childrenOptions;
                if (that.hasChildren) {
                    that._initChildren();
                }
                that._loaded = !!(value && value._loaded);
            },
            _initChildren: function () {
                var that = this;
                var children, transport, parameterMap;
                if (!(that.children instanceof HierarchicalDataSource)) {
                    children = that.children = new HierarchicalDataSource(that._childrenOptions);
                    transport = children.transport;
                    parameterMap = transport.parameterMap;
                    transport.parameterMap = function (data, type) {
                        data[that.idField || 'id'] = that.id;
                        if (parameterMap) {
                            data = parameterMap(data, type);
                        }
                        return data;
                    };
                    children.parent = function () {
                        return that;
                    };
                    children.bind(CHANGE, function (e) {
                        e.node = e.node || that;
                        that.trigger(CHANGE, e);
                    });
                    children.bind(ERROR, function (e) {
                        var collection = that.parent();
                        if (collection) {
                            e.node = e.node || that;
                            collection.trigger(ERROR, e);
                        }
                    });
                    that._updateChildrenField();
                }
            },
            append: function (model) {
                this._initChildren();
                this.loaded(true);
                this.children.add(model);
            },
            hasChildren: false,
            level: function () {
                var parentNode = this.parentNode(), level = 0;
                while (parentNode && parentNode.parentNode) {
                    level++;
                    parentNode = parentNode.parentNode ? parentNode.parentNode() : null;
                }
                return level;
            },
            _updateChildrenField: function () {
                var fieldName = this._childrenOptions.schema.data;
                this[fieldName || 'items'] = this.children.data();
            },
            _childrenLoaded: function () {
                this._loaded = true;
                this._updateChildrenField();
            },
            load: function () {
                var options = {};
                var method = '_query';
                var children, promise;
                if (this.hasChildren) {
                    this._initChildren();
                    children = this.children;
                    options[this.idField || 'id'] = this.id;
                    if (!this._loaded) {
                        children._data = undefined;
                        method = 'read';
                    }
                    children.one(CHANGE, proxy(this._childrenLoaded, this));
                    if (this._matchFilter) {
                        options.filter = {
                            field: '_matchFilter',
                            operator: 'eq',
                            value: true
                        };
                    }
                    promise = children[method](options);
                } else {
                    this.loaded(true);
                }
                return promise || $.Deferred().resolve().promise();
            },
            parentNode: function () {
                var array = this.parent();
                return array.parent();
            },
            loaded: function (value) {
                if (value !== undefined) {
                    this._loaded = value;
                } else {
                    return this._loaded;
                }
            },
            shouldSerialize: function (field) {
                return Model.fn.shouldSerialize.call(this, field) && field !== 'children' && field !== '_loaded' && field !== 'hasChildren' && field !== '_childrenOptions';
            }
        });
        function dataMethod(name) {
            return function () {
                var data = this._data, result = DataSource.fn[name].apply(this, slice.call(arguments));
                if (this._data != data) {
                    this._attachBubbleHandlers();
                }
                return result;
            };
        }
        var HierarchicalDataSource = DataSource.extend({
            init: function (options) {
                var node = Node.define({ children: options });
                if (options.filter && !options.serverFiltering) {
                    this._hierarchicalFilter = options.filter;
                    options.filter = null;
                }
                DataSource.fn.init.call(this, extend(true, {}, {
                    schema: {
                        modelBase: node,
                        model: node
                    }
                }, options));
                this._attachBubbleHandlers();
            },
            _attachBubbleHandlers: function () {
                var that = this;
                that._data.bind(ERROR, function (e) {
                    that.trigger(ERROR, e);
                });
            },
            read: function (data) {
                var result = DataSource.fn.read.call(this, data);
                if (this._hierarchicalFilter) {
                    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;
                this.xRotation = options.xRotation;
            },
            clone: function () {
                return new Arc$2(this.center, {
                    radiusX: this.radiusX,
                    radiusY: this.radiusY,
                    startAngle: this.startAngle,
                    endAngle: this.endAngle,
                    anticlockwise: this.anticlockwise
                });
            },
            setCenter: function (value) {
                this._observerField('center', Point.create(value));
                this.geometryChange();
                return this;
            },
            getCenter: function () {
                return this.center;
            },
            pointAt: function (angle) {
                var center = this.center;
                var radian = rad(angle);
                return new Point(center.x + this.radiusX * Math.cos(radian), center.y + this.radiusY * Math.sin(radian));
            },
            curvePoints: function () {
                var this$1 = this;
                var startAngle = this.startAngle;
                var dir = this.anticlockwise ? -1 : 1;
                var curvePoints = [this.pointAt(startAngle)];
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var subIntervalsCount = Math.ceil(intervalAngle / MAX_INTERVAL);
                var subIntervalAngle = intervalAngle / subIntervalsCount;
                var currentAngle = startAngle;
                var transformation;
                if (this.xRotation) {
                    transformation = transform().rotate(this.xRotation, this.center);
                }
                for (var i = 1; i <= subIntervalsCount; i++) {
                    var nextAngle = currentAngle + dir * subIntervalAngle;
                    var points = this$1._intervalCurvePoints(currentAngle, nextAngle, transformation);
                    curvePoints.push(points.cp1, points.cp2, points.p2);
                    currentAngle = nextAngle;
                }
                return curvePoints;
            },
            bbox: function (matrix) {
                var this$1 = this;
                var interval = this._arcInterval();
                var startAngle = interval.startAngle;
                var endAngle = interval.endAngle;
                var extremeAngles = ellipseExtremeAngles(this.center, this.radiusX, this.radiusY, matrix);
                var extremeX = deg(extremeAngles.x);
                var extremeY = deg(extremeAngles.y);
                var endPoint = this.pointAt(endAngle).transformCopy(matrix);
                var currentAngleX = bboxStartAngle(extremeX, startAngle);
                var currentAngleY = bboxStartAngle(extremeY, startAngle);
                var currentPoint = this.pointAt(startAngle).transformCopy(matrix);
                var minPoint = Point.min(currentPoint, endPoint);
                var maxPoint = Point.max(currentPoint, endPoint);
                while (currentAngleX < endAngle || currentAngleY < endAngle) {
                    var currentPointX = void 0;
                    if (currentAngleX < endAngle) {
                        currentPointX = this$1.pointAt(currentAngleX).transformCopy(matrix);
                        currentAngleX += 90;
                    }
                    var currentPointY = void 0;
                    if (currentAngleY < endAngle) {
                        currentPointY = this$1.pointAt(currentAngleY).transformCopy(matrix);
                        currentAngleY += 90;
                    }
                    currentPoint = new Point(currentPointX.x, currentPointY.y);
                    minPoint = Point.min(minPoint, currentPoint);
                    maxPoint = Point.max(maxPoint, currentPoint);
                }
                return Rect.fromPoints(minPoint, maxPoint);
            },
            _arcInterval: function () {
                var ref = this;
                var startAngle = ref.startAngle;
                var endAngle = ref.endAngle;
                var anticlockwise = ref.anticlockwise;
                if (anticlockwise) {
                    var oldStart = startAngle;
                    startAngle = endAngle;
                    endAngle = oldStart;
                }
                if (startAngle > endAngle || anticlockwise && startAngle === endAngle) {
                    endAngle += 360;
                }
                return {
                    startAngle: startAngle,
                    endAngle: endAngle
                };
            },
            _intervalCurvePoints: function (startAngle, endAngle, transformation) {
                var p1 = this.pointAt(startAngle);
                var p2 = this.pointAt(endAngle);
                var p1Derivative = this._derivativeAt(startAngle);
                var p2Derivative = this._derivativeAt(endAngle);
                var t = (rad(endAngle) - rad(startAngle)) / 3;
                var cp1 = new Point(p1.x + t * p1Derivative.x, p1.y + t * p1Derivative.y);
                var cp2 = new Point(p2.x - t * p2Derivative.x, p2.y - t * p2Derivative.y);
                if (transformation) {
                    p1.transform(transformation);
                    p2.transform(transformation);
                    cp1.transform(transformation);
                    cp2.transform(transformation);
                }
                return {
                    p1: p1,
                    cp1: cp1,
                    cp2: cp2,
                    p2: p2
                };
            },
            _derivativeAt: function (angle) {
                var radian = rad(angle);
                return new Point(-this.radiusX * Math.sin(radian), this.radiusY * Math.cos(radian));
            },
            containsPoint: function (point) {
                var interval = this._arcInterval();
                var intervalAngle = interval.endAngle - interval.startAngle;
                var ref = this;
                var center = ref.center;
                var radiusX = ref.radiusX;
                var radiusY = ref.radiusY;
                var distance = center.distanceTo(point);
                var angleRad = Math.atan2(point.y - center.y, point.x - center.x);
                var pointRadius = radiusX * radiusY / Math.sqrt(pow$1(radiusX, 2) * pow$1(Math.sin(angleRad), 2) + pow$1(radiusY, 2) * pow$1(Math.cos(angleRad), 2));
                var startPoint = this.pointAt(this.startAngle).round(PRECISION);
                var endPoint = this.pointAt(this.endAngle).round(PRECISION);
                var intersection = lineIntersection(center, point.round(PRECISION), startPoint, endPoint);
                var containsPoint;
                if (intervalAngle < 180) {
                    containsPoint = intersection && closeOrLess(center.distanceTo(intersection), distance) && closeOrLess(distance, pointRadius);
                } else {
                    var angle = calculateAngle(center.x, center.y, radiusX, radiusY, point.x, point.y);
                    if (angle !== 360) {
                        angle = (360 + angle) % 360;
                    }
                    var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
                    containsPoint = inAngleRange && closeOrLess(distance, pointRadius) || !inAngleRange && (!intersection || intersection.equals(point));
                }
                return containsPoint;
            },
            _isOnPath: function (point, width) {
                var interval = this._arcInterval();
                var center = this.center;
                var angle = calculateAngle(center.x, center.y, this.radiusX, this.radiusY, point.x, point.y);
                if (angle !== 360) {
                    angle = (360 + angle) % 360;
                }
                var inAngleRange = interval.startAngle <= angle && angle <= interval.endAngle;
                return inAngleRange && this.pointAt(angle).distanceTo(point) <= width;
            }
        });
        Arc$2.fromPoints = function (start, end, rx, ry, largeArc, swipe, rotation) {
            var arcParameters = normalizeArcParameters({
                x1: start.x,
                y1: start.y,
                x2: end.x,
                y2: end.y,
                rx: rx,
                ry: ry,
                largeArc: largeArc,
                swipe: swipe,
                rotation: rotation
            });
            return new Arc$2(arcParameters.center, {
                startAngle: arcParameters.startAngle,
                endAngle: arcParameters.endAngle,
                radiusX: arcParameters.radiusX,
                radiusY: arcParameters.radiusY,
                xRotation: arcParameters.xRotation,
                anticlockwise: swipe === 0
            });
        };
        defineAccessors(Arc$2.prototype, [
            'radiusX',
            'radiusY',
            'startAngle',
            'endAngle',
            'anticlockwise'
        ]);
        ObserversMixin.extend(Arc$2.prototype);
        function calculateAngle(cx, cy, rx, ry, x, y) {
            var cos = round((x - cx) / rx, 3);
            var sin = round((y - cy) / ry, 3);
            return round(deg(Math.atan2(sin, cos)));
        }
        function normalizeArcParameters(parameters) {
            var x1 = parameters.x1;
            var y1 = parameters.y1;
            var x2 = parameters.x2;
            var y2 = parameters.y2;
            var rx = parameters.rx;
            var ry = parameters.ry;
            var largeArc = parameters.largeArc;
            var swipe = parameters.swipe;
            var rotation = parameters.rotation;
            if (rotation === void 0) {
                rotation = 0;
            }
            var radians = rad(rotation);
            var cosine = Math.cos(radians);
            var sine = Math.sin(radians);
            var xT = cosine * (x1 - x2) / 2 + sine * (y1 - y2) / 2;
            var yT = -sine * (x1 - x2) / 2 + cosine * (y1 - y2) / 2;
            var sign = largeArc !== swipe ? 1 : -1;
            var xt2 = Math.pow(xT, 2);
            var yt2 = Math.pow(yT, 2);
            var rx2 = Math.pow(rx, 2);
            var ry2 = Math.pow(ry, 2);
            var delta = xt2 / rx2 + yt2 / ry2;
            if (delta > 1) {
                delta = Math.sqrt(xt2 / rx2 + yt2 / ry2);
                rx = delta * rx;
                rx2 = Math.pow(rx, 2);
                ry = delta * ry;
                ry2 = Math.pow(ry, 2);
            }
            var constT = sign * Math.sqrt((rx2 * ry2 - rx2 * yt2 - ry2 * xt2) / (rx2 * yt2 + ry2 * xt2));
            if (isNaN(constT)) {
                constT = 0;
            }
            var cxT = constT * (rx * yT) / ry;
            var cyT = -constT * (ry * xT) / rx;
            var cx = cosine * cxT - sine * cyT + (x1 + x2) / 2;
            var cy = sine * cxT + cosine * cyT + (y1 + y2) / 2;
            var uX = (xT - cxT) / rx;
            var uY = (yT - cyT) / ry;
            var vX = -(xT + cxT) / rx;
            var vY = -(yT + cyT) / ry;
            var startAngle = (uY >= 0 ? 1 : -1) * deg(Math.acos(uX / Math.sqrt(uX * uX + uY * uY)));
            var angleCosine = round((uX * vX + uY * vY) / (Math.sqrt(uX * uX + uY * uY) * Math.sqrt(vX * vX + vY * vY)), 10);
            var angle = (uX * vY - uY * vX >= 0 ? 1 : -1) * deg(Math.acos(angleCosine));
            if (!swipe && angle > 0) {
                angle -= 360;
            }
            if (swipe && angle < 0) {
                angle += 360;
            }
            var endAngle = startAngle + angle;
            var signEndAngle = endAngle >= 0 ? 1 : -1;
            endAngle = Math.abs(endAngle) % 360 * signEndAngle;
            return {
                center: new Point(cx, cy),
                startAngle: startAngle,
                endAngle: endAngle,
                radiusX: rx,
                radiusY: ry,
                xRotation: rotation
            };
        }
        function bboxStartAngle(angle, start) {
            var startAngle = angle;
            while (startAngle < start) {
                startAngle += 90;
            }
            return startAngle;
        }
        var push = [].push;
        var pop = [].pop;
        var splice = [].splice;
        var shift = [].shift;
        var slice = [].slice;
        var unshift = [].unshift;
        var ElementsArray = Class.extend({
            init: function (array) {
                if (array === void 0) {
                    array = [];
                }
                this.length = 0;
                this._splice(0, array.length, array);
            },
            elements: function (value) {
                if (value) {
                    this._splice(0, this.length, value);
                    this._change();
                    return this;
                }
                return this.slice(0);
            },
            push: function () {
                var elements = arguments;
                var result = push.apply(this, elements);
                this._add(elements);
                return result;
            },
            slice: function () {
                return slice.call(this);
            },
            pop: function () {
                var length = this.length;
                var result = pop.apply(this);
                if (length) {
                    this._remove([result]);
                }
                return result;
            },
            splice: function (index, howMany) {
                var elements = slice.call(arguments, 2);
                var result = this._splice(index, howMany, elements);
                this._change();
                return result;
            },
            shift: function () {
                var length = this.length;
                var result = shift.apply(this);
                if (length) {
                    this._remove([result]);
                }
                return result;
            },
            unshift: function () {
                var elements = arguments;
                var result = unshift.apply(this, elements);
                this._add(elements);
                return result;
            },
            indexOf: function (element) {
                var this$1 = this;
                var length = this.length;
                for (var idx = 0; idx < length; idx++) {
                    if (this$1[idx] === element) {
                        return idx;
                    }
                }
                return -1;
            },
            _splice: function (index, howMany, elements) {
                var result = splice.apply(this, [
                    index,
                    howMany
                ].concat(elements));
                this._clearObserver(result);
                this._setObserver(elements);
                return result;
            },
            _add: function (elements) {
                this._setObserver(elements);
                this._change();
            },
            _remove: function (elements) {
                this._clearObserver(elements);
                this._change();
            },
            _setObserver: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].addObserver(this$1);
                }
            },
            _clearObserver: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    elements[idx].removeObserver(this$1);
                }
            },
            _change: function () {
            }
        });
        ObserversMixin.extend(ElementsArray.prototype);
        var GeometryElementsArray = ElementsArray.extend({
            _change: function () {
                this.geometryChange();
            }
        });
        function pointAccessor(name) {
            var fieldName = '_' + name;
            return function (value) {
                if (defined(value)) {
                    this._observerField(fieldName, Point.create(value));
                    this.geometryChange();
                    return this;
                }
                return this[fieldName];
            };
        }
        function definePointAccessors(fn, names) {
            for (var i = 0; i < names.length; i++) {
                fn[names[i]] = pointAccessor(names[i]);
            }
        }
        function isOutOfEndPoint(endPoint, controlPoint, point) {
            var angle = deg(Math.atan2(controlPoint.y - endPoint.y, controlPoint.x - endPoint.x));
            var rotatedPoint = point.transformCopy(transform().rotate(-angle, endPoint));
            return rotatedPoint.x < endPoint.x;
        }
        function calculateCurveAt(t, field, points) {
            var t1 = 1 - t;
            return Math.pow(t1, 3) * points[0][field] + 3 * Math.pow(t1, 2) * t * points[1][field] + 3 * Math.pow(t, 2) * t1 * points[2][field] + Math.pow(t, 3) * points[3][field];
        }
        function toCubicPolynomial(points, field) {
            return [
                -points[0][field] + 3 * points[1][field] - 3 * points[2][field] + points[3][field],
                3 * (points[0][field] - 2 * points[1][field] + points[2][field]),
                3 * (-points[0][field] + points[1][field]),
                points[0][field]
            ];
        }
        var ComplexNumber = Class.extend({
            init: function (real, img) {
                if (real === void 0) {
                    real = 0;
                }
                if (img === void 0) {
                    img = 0;
                }
                this.real = real;
                this.img = img;
            },
            add: function (cNumber) {
                return new ComplexNumber(round(this.real + cNumber.real, PRECISION), round(this.img + cNumber.img, PRECISION));
            },
            addConstant: function (value) {
                return new ComplexNumber(this.real + value, this.img);
            },
            negate: function () {
                return new ComplexNumber(-this.real, -this.img);
            },
            multiply: function (cNumber) {
                return new ComplexNumber(this.real * cNumber.real - this.img * cNumber.img, this.real * cNumber.img + this.img * cNumber.real);
            },
            multiplyConstant: function (value) {
                return new ComplexNumber(this.real * value, this.img * value);
            },
            nthRoot: function (n) {
                var rad$$1 = Math.atan2(this.img, this.real);
                var r = Math.sqrt(Math.pow(this.img, 2) + Math.pow(this.real, 2));
                var nthR = Math.pow(r, 1 / n);
                return new ComplexNumber(nthR * Math.cos(rad$$1 / n), nthR * Math.sin(rad$$1 / n));
            },
            equals: function (cNumber) {
                return this.real === cNumber.real && this.img === cNumber.img;
            },
            isReal: function () {
                return this.img === 0;
            }
        });
        function numberSign(x) {
            return x < 0 ? -1 : 1;
        }
        function solveQuadraticEquation(a, b, c) {
            var squareRoot = Math.sqrt(Math.pow(b, 2) - 4 * a * c);
            return [
                (-b + squareRoot) / (2 * a),
                (-b - squareRoot) / (2 * a)
            ];
        }
        function solveCubicEquation(a, b, c, d) {
            if (a === 0) {
                return solveQuadraticEquation(b, c, d);
            }
            var p = (3 * a * c - Math.pow(b, 2)) / (3 * Math.pow(a, 2));
            var q = (2 * Math.pow(b, 3) - 9 * a * b * c + 27 * Math.pow(a, 2) * d) / (27 * Math.pow(a, 3));
            var Q = Math.pow(p / 3, 3) + Math.pow(q / 2, 2);
            var i = new ComplexNumber(0, 1);
            var b3a = -b / (3 * a);
            var x1, x2, y1, y2, y3, z1, z2;
            if (Q < 0) {
                x1 = new ComplexNumber(-q / 2, Math.sqrt(-Q)).nthRoot(3);
                x2 = new ComplexNumber(-q / 2, -Math.sqrt(-Q)).nthRoot(3);
            } else {
                x1 = -q / 2 + Math.sqrt(Q);
                x1 = new ComplexNumber(numberSign(x1) * Math.pow(Math.abs(x1), 1 / 3));
                x2 = -q / 2 - Math.sqrt(Q);
                x2 = new ComplexNumber(numberSign(x2) * Math.pow(Math.abs(x2), 1 / 3));
            }
            y1 = x1.add(x2);
            z1 = x1.add(x2).multiplyConstant(-1 / 2);
            z2 = x1.add(x2.negate()).multiplyConstant(Math.sqrt(3) / 2);
            y2 = z1.add(i.multiply(z2));
            y3 = z1.add(i.negate().multiply(z2));
            var result = [];
            if (y1.isReal()) {
                result.push(round(y1.real + b3a, PRECISION));
            }
            if (y2.isReal()) {
                result.push(round(y2.real + b3a, PRECISION));
            }
            if (y3.isReal()) {
                result.push(round(y3.real + b3a, PRECISION));
            }
            return result;
        }
        function hasRootsInRange(points, point, field, rootField, range) {
            var polynomial = toCubicPolynomial(points, rootField);
            var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point[rootField]);
            var intersection;
            for (var idx = 0; idx < roots.length; idx++) {
                if (0 <= roots[idx] && roots[idx] <= 1) {
                    intersection = calculateCurveAt(roots[idx], field, points);
                    if (Math.abs(intersection - point[field]) <= range) {
                        return true;
                    }
                }
            }
        }
        function curveIntersectionsCount(points, point, bbox) {
            var polynomial = toCubicPolynomial(points, 'x');
            var roots = solveCubicEquation(polynomial[0], polynomial[1], polynomial[2], polynomial[3] - point.x);
            var rayIntersection, intersectsRay;
            var count = 0;
            for (var i = 0; i < roots.length; i++) {
                rayIntersection = calculateCurveAt(roots[i], 'y', points);
                intersectsRay = close(rayIntersection, point.y) || rayIntersection > point.y;
                if (intersectsRay && ((roots[i] === 0 || roots[i] === 1) && bbox.bottomRight().x > point.x || 0 < roots[i] && roots[i] < 1)) {
                    count++;
                }
            }
            return count;
        }
        function lineIntersectionsCount(a, b, point) {
            var intersects;
            if (a.x !== b.x) {
                var minX = Math.min(a.x, b.x);
                var maxX = Math.max(a.x, b.x);
                var minY = Math.min(a.y, b.y);
                var maxY = Math.max(a.y, b.y);
                var inRange = minX <= point.x && point.x < maxX;
                if (minY === maxY) {
                    intersects = point.y <= minY && inRange;
                } else {
                    intersects = inRange && (maxY - minY) * ((a.x - b.x) * (a.y - b.y) > 0 ? point.x - minX : maxX - point.x) / (maxX - minX) + minY - point.y >= 0;
                }
            }
            return intersects ? 1 : 0;
        }
        var Segment = Class.extend({
            init: function (anchor, controlIn, controlOut) {
                this.anchor(anchor || new Point());
                this.controlIn(controlIn);
                this.controlOut(controlOut);
            },
            bboxTo: function (toSegment, matrix) {
                var segmentAnchor = this.anchor().transformCopy(matrix);
                var toSegmentAnchor = toSegment.anchor().transformCopy(matrix);
                var rect;
                if (this.controlOut() && toSegment.controlIn()) {
                    rect = this._curveBoundingBox(segmentAnchor, this.controlOut().transformCopy(matrix), toSegment.controlIn().transformCopy(matrix), toSegmentAnchor);
                } else {
                    rect = this._lineBoundingBox(segmentAnchor, toSegmentAnchor);
                }
                return rect;
            },
            _lineBoundingBox: function (p1, p2) {
                return Rect.fromPoints(p1, p2);
            },
            _curveBoundingBox: function (p1, cp1, cp2, p2) {
                var points = [
                    p1,
                    cp1,
                    cp2,
                    p2
                ];
                var extremesX = this._curveExtremesFor(points, 'x');
                var extremesY = this._curveExtremesFor(points, 'y');
                var xLimits = arrayLimits([
                    extremesX.min,
                    extremesX.max,
                    p1.x,
                    p2.x
                ]);
                var yLimits = arrayLimits([
                    extremesY.min,
                    extremesY.max,
                    p1.y,
                    p2.y
                ]);
                return Rect.fromPoints(new Point(xLimits.min, yLimits.min), new Point(xLimits.max, yLimits.max));
            },
            _curveExtremesFor: function (points, field) {
                var extremes = this._curveExtremes(points[0][field], points[1][field], points[2][field], points[3][field]);
                return {
                    min: calculateCurveAt(extremes.min, field, points),
                    max: calculateCurveAt(extremes.max, field, points)
                };
            },
            _curveExtremes: function (x1, x2, x3, x4) {
                var a = x1 - 3 * x2 + 3 * x3 - x4;
                var b = -2 * (x1 - 2 * x2 + x3);
                var c = x1 - x2;
                var sqrt = Math.sqrt(b * b - 4 * a * c);
                var t1 = 0;
                var t2 = 1;
                if (a === 0) {
                    if (b !== 0) {
                        t1 = t2 = -c / b;
                    }
                } else if (!isNaN(sqrt)) {
                    t1 = (-b + sqrt) / (2 * a);
                    t2 = (-b - sqrt) / (2 * a);
                }
                var min = Math.max(Math.min(t1, t2), 0);
                if (min < 0 || min > 1) {
                    min = 0;
                }
                var max = Math.min(Math.max(t1, t2), 1);
                if (max > 1 || max < 0) {
                    max = 1;
                }
                return {
                    min: min,
                    max: max
                };
            },
            _intersectionsTo: function (segment, point) {
                var intersectionsCount;
                if (this.controlOut() && segment.controlIn()) {
                    intersectionsCount = curveIntersectionsCount([
                        this.anchor(),
                        this.controlOut(),
                        segment.controlIn(),
                        segment.anchor()
                    ], point, this.bboxTo(segment));
                } else {
                    intersectionsCount = lineIntersectionsCount(this.anchor(), segment.anchor(), point);
                }
                return intersectionsCount;
            },
            _isOnCurveTo: function (segment, point, width, endSegment) {
                var bbox = this.bboxTo(segment).expand(width, width);
                if (bbox.containsPoint(point)) {
                    var p1 = this.anchor();
                    var p2 = this.controlOut();
                    var p3 = segment.controlIn();
                    var p4 = segment.anchor();
                    if (endSegment === 'start' && p1.distanceTo(point) <= width) {
                        return !isOutOfEndPoint(p1, p2, point);
                    } else if (endSegment === 'end' && p4.distanceTo(point) <= width) {
                        return !isOutOfEndPoint(p4, p3, point);
                    }
                    var points = [
                        p1,
                        p2,
                        p3,
                        p4
                    ];
                    if (hasRootsInRange(points, point, 'x', 'y', width) || hasRootsInRange(points, point, 'y', 'x', width)) {
                        return true;
                    }
                    var rotation = transform().rotate(45, point);
                    var rotatedPoints = [
                        p1.transformCopy(rotation),
                        p2.transformCopy(rotation),
                        p3.transformCopy(rotation),
                        p4.transformCopy(rotation)
                    ];
                    return hasRootsInRange(rotatedPoints, point, 'x', 'y', width) || hasRootsInRange(rotatedPoints, point, 'y', 'x', width);
                }
            },
            _isOnLineTo: function (segment, point, width) {
                var p1 = this.anchor();
                var p2 = segment.anchor();
                var angle = deg(Math.atan2(p2.y - p1.y, p2.x - p1.x));
                var rect = new Rect([
                    p1.x,
                    p1.y - width / 2
                ], [
                    p1.distanceTo(p2),
                    width
                ]);
                return rect.containsPoint(point.transformCopy(transform().rotate(-angle, p1)));
            },
            _isOnPathTo: function (segment, point, width, endSegment) {
                var isOnPath;
                if (this.controlOut() && segment.controlIn()) {
                    isOnPath = this._isOnCurveTo(segment, point, width / 2, endSegment);
                } else {
                    isOnPath = this._isOnLineTo(segment, point, width);
                }
                return isOnPath;
            }
        });
        definePointAccessors(Segment.prototype, [
            'anchor',
            'controlIn',
            'controlOut'
        ]);
        ObserversMixin.extend(Segment.prototype);
        function arrayLimits(arr) {
            var length = arr.length;
            var min = MAX_NUM;
            var max = MIN_NUM;
            for (var i = 0; i < length; i++) {
                max = Math.max(max, arr[i]);
                min = Math.min(min, arr[i]);
            }
            return {
                min: min,
                max: max
            };
        }
        var Path = Element$1.extend({
            init: function (options) {
                Element$1.fn.init.call(this, options);
                this.segments = new GeometryElementsArray();
                this.segments.addObserver(this);
                if (!defined(this.options.stroke)) {
                    this.stroke('#000');
                    if (!defined(this.options.stroke.lineJoin)) {
                        this.options.set('stroke.lineJoin', 'miter');
                    }
                }
            },
            moveTo: function (x, y) {
                this.suspend();
                this.segments.elements([]);
                this.resume();
                this.lineTo(x, y);
                return this;
            },
            lineTo: function (x, y) {
                var point = defined(y) ? new Point(x, y) : x;
                var segment = new Segment(point);
                this.segments.push(segment);
                return this;
            },
            curveTo: function (controlOut, controlIn, point) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var segment = new Segment(point, controlIn);
                    this.suspend();
                    lastSegment.controlOut(controlOut);
                    this.resume();
                    this.segments.push(segment);
                }
                return this;
            },
            arc: function (startAngle, endAngle, radiusX, radiusY, anticlockwise) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var anchor = lastSegment.anchor();
                    var start = rad(startAngle);
                    var center = new Point(anchor.x - radiusX * Math.cos(start), anchor.y - radiusY * Math.sin(start));
                    var arc = new Arc$2(center, {
                        startAngle: startAngle,
                        endAngle: endAngle,
                        radiusX: radiusX,
                        radiusY: radiusY,
                        anticlockwise: anticlockwise
                    });
                    this._addArcSegments(arc);
                }
                return this;
            },
            arcTo: function (end, rx, ry, largeArc, swipe, rotation) {
                if (this.segments.length > 0) {
                    var lastSegment = last(this.segments);
                    var anchor = lastSegment.anchor();
                    var arc = Arc$2.fromPoints(anchor, end, rx, ry, largeArc, swipe, rotation);
                    this._addArcSegments(arc);
                }
                return this;
            },
            _addArcSegments: function (arc) {
                var this$1 = this;
                this.suspend();
                var curvePoints = arc.curvePoints();
                for (var i = 1; i < curvePoints.length; i += 3) {
                    this$1.curveTo(curvePoints[i], curvePoints[i + 1], curvePoints[i + 2]);
                }
                this.resume();
                this.geometryChange();
            },
            close: function () {
                this.options.closed = true;
                this.geometryChange();
                return this;
            },
            rawBBox: function () {
                return this._bbox();
            },
            _containsPoint: function (point) {
                var segments = this.segments;
                var length = segments.length;
                var intersectionsCount = 0;
                var previous, current;
                for (var idx = 1; idx < length; idx++) {
                    previous = segments[idx - 1];
                    current = segments[idx];
                    intersectionsCount += previous._intersectionsTo(current, point);
                }
                if (this.options.closed || !segments[0].anchor().equals(segments[length - 1].anchor())) {
                    intersectionsCount += lineIntersectionsCount(segments[0].anchor(), segments[length - 1].anchor(), point);
                }
                return intersectionsCount % 2 !== 0;
            },
            _isOnPath: function (point, width) {
                var segments = this.segments;
                var length = segments.length;
                var pathWidth = width || this.options.stroke.width;
                if (length > 1) {
                    if (segments[0]._isOnPathTo(segments[1], point, pathWidth, 'start')) {
                        return true;
                    }
                    for (var idx = 2; idx <= length - 2; idx++) {
                        if (segments[idx - 1]._isOnPathTo(segments[idx], point, pathWidth)) {
                            return true;
                        }
                    }
                    if (segments[length - 2]._isOnPathTo(segments[length - 1], point, pathWidth, 'end')) {
                        return true;
                    }
                }
                return false;
            },
            _bbox: function (matrix) {
                var segments = this.segments;
                var length = segments.length;
                var boundingBox;
                if (length === 1) {
                    var anchor = segments[0].anchor().transformCopy(matrix);
                    boundingBox = new Rect(anchor, Size.ZERO);
                } else if (length > 0) {
                    for (var i = 1; i < length; i++) {
                        var segmentBox = segments[i - 1].bboxTo(segments[i], matrix);
                        if (boundingBox) {
                            boundingBox = Rect.union(boundingBox, segmentBox);
                        } else {
                            boundingBox = segmentBox;
                        }
                    }
                }
                return boundingBox;
            }
        });
        Path.fromRect = function (rect, options) {
            return new Path(options).moveTo(rect.topLeft()).lineTo(rect.topRight()).lineTo(rect.bottomRight()).lineTo(rect.bottomLeft()).close();
        };
        Path.fromPoints = function (points, options) {
            if (points) {
                var path = new Path(options);
                for (var i = 0; i < points.length; i++) {
                    var point = Point.create(points[i]);
                    if (point) {
                        if (i === 0) {
                            path.moveTo(point);
                        } else {
                            path.lineTo(point);
                        }
                    }
                }
                return path;
            }
        };
        Path.fromArc = function (arc, options) {
            var path = new Path(options);
            var startAngle = arc.startAngle;
            var start = arc.pointAt(startAngle);
            path.moveTo(start.x, start.y);
            path.arc(startAngle, arc.endAngle, arc.radiusX, arc.radiusY, arc.anticlockwise);
            return path;
        };
        Path.prototype.nodeType = 'Path';
        Paintable.extend(Path.prototype);
        Measurable.extend(Path.prototype);
        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, rotation) {
                if (this.paths.length > 0) {
                    last(this.paths).arcTo(end, rx, ry, largeArc, swipe, rotation);
                }
                return this;
            },
            close: function () {
                if (this.paths.length > 0) {
                    last(this.paths).close();
                }
                return this;
            },
            _bbox: function (matrix) {
                return elementsBoundingBox(this.paths, true, matrix);
            },
            rawBBox: function () {
                return elementsBoundingBox(this.paths, false);
            },
            _containsPoint: function (point) {
                var paths = this.paths;
                for (var idx = 0; idx < paths.length; idx++) {
                    if (paths[idx]._containsPoint(point)) {
                        return true;
                    }
                }
                return false;
            },
            _isOnPath: function (point) {
                var paths = this.paths;
                var width = this.options.stroke.width;
                for (var idx = 0; idx < paths.length; idx++) {
                    if (paths[idx]._isOnPath(point, width)) {
                        return true;
                    }
                }
                return false;
            },
            _clippedBBox: function (transformation) {
                return elementsClippedBoundingBox(this.paths, this.currentTransform(transformation));
            }
        });
        MultiPath.prototype.nodeType = 'MultiPath';
        Paintable.extend(MultiPath.prototype);
        Measurable.extend(MultiPath.prototype);
        var 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 rotation = parameters[i + 2];
                    var largeArc = parameters[i + 3];
                    var swipe = parameters[i + 4];
                    var endPoint = new Point(parameters[i + 5], parameters[i + 6]);
                    if (options.isRelative) {
                        endPoint.translateWith(position);
                    }
                    if (position.x !== endPoint.x || position.y !== endPoint.y) {
                        path.arcTo(endPoint, radiusX, radiusY, largeArc, swipe, rotation);
                        position.x = endPoint.x;
                        position.y = endPoint.y;
                    }
                }
            },
            s: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                var previousCommand = options.previousCommand;
                var lastControlIn;
                if (previousCommand === 's' || previousCommand === 'c') {
                    lastControlIn = last(last(path.paths).segments).controlIn();
                }
                for (var i = 0; i < parameters.length; i += 4) {
                    var controlIn = new Point(parameters[i], parameters[i + 1]);
                    var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    var controlOut = void 0;
                    if (options.isRelative) {
                        controlIn.translateWith(position);
                        endPoint.translateWith(position);
                    }
                    if (lastControlIn) {
                        controlOut = reflectionPoint(lastControlIn, position);
                    } else {
                        controlOut = position.clone();
                    }
                    lastControlIn = controlIn;
                    path.curveTo(controlOut, controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            },
            q: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                for (var i = 0; i < parameters.length; i += 4) {
                    var controlPoint = new Point(parameters[i], parameters[i + 1]);
                    var endPoint = new Point(parameters[i + 2], parameters[i + 3]);
                    if (options.isRelative) {
                        controlPoint.translateWith(position);
                        endPoint.translateWith(position);
                    }
                    var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
                    path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            },
            t: function (path, options) {
                var parameters = options.parameters;
                var position = options.position;
                var previousCommand = options.previousCommand;
                var controlPoint;
                if (previousCommand === 'q' || previousCommand === 't') {
                    var lastSegment = last(last(path.paths).segments);
                    controlPoint = lastSegment.controlIn().clone().translateWith(position.scaleCopy(-1 / 3)).scale(3 / 2);
                }
                for (var i = 0; i < parameters.length; i += 2) {
                    var endPoint = new Point(parameters[i], parameters[i + 1]);
                    if (options.isRelative) {
                        endPoint.translateWith(position);
                    }
                    if (controlPoint) {
                        controlPoint = reflectionPoint(controlPoint, position);
                    } else {
                        controlPoint = position.clone();
                    }
                    var cubicControlPoints = quadraticToCubicControlPoints(position, controlPoint, endPoint);
                    path.curveTo(cubicControlPoints.controlOut, cubicControlPoints.controlIn, endPoint);
                    position.x = endPoint.x;
                    position.y = endPoint.y;
                }
            }
        };
        function toLineParamaters(parameters, isVertical, value) {
            var insertPosition = isVertical ? 0 : 1;
            for (var i = 0; i < parameters.length; i += 2) {
                parameters.splice(i + insertPosition, 0, value);
            }
        }
        function reflectionPoint(point, center) {
            if (point && center) {
                return center.scaleCopy(2).translate(-point.x, -point.y);
            }
        }
        var third = 1 / 3;
        function quadraticToCubicControlPoints(position, controlPoint, endPoint) {
            var scaledPoint = controlPoint.clone().scale(2 / 3);
            return {
                controlOut: scaledPoint.clone().translateWith(position.scaleCopy(third)),
                controlIn: scaledPoint.translateWith(endPoint.scaleCopy(third))
            };
        }
        var SEGMENT_REGEX = /([a-df-z]{1})([^a-df-z]*)(z)?/gi;
        var SPLIT_REGEX = /[,\s]?([+\-]?(?:\d*\.\d+|\d+)(?:[eE][+\-]?\d+)?)/g;
        var MOVE = 'm';
        var CLOSE = 'z';
        function parseParameters(str) {
            var parameters = [];
            str.replace(SPLIT_REGEX, function (match, number) {
                parameters.push(parseFloat(number));
            });
            return parameters;
        }
        var PathParser = Class.extend({
            parse: function (str, options) {
                var multiPath = new MultiPath(options);
                var position = new Point();
                var previousCommand;
                str.replace(SEGMENT_REGEX, function (match, element, params, closePath) {
                    var command = element.toLowerCase();
                    var isRelative = command === element;
                    var parameters = parseParameters(params.trim());
                    if (command === MOVE) {
                        if (isRelative) {
                            position.x += parameters[0];
                            position.y += parameters[1];
                        } else {
                            position.x = parameters[0];
                            position.y = parameters[1];
                        }
                        multiPath.moveTo(position.x, position.y);
                        if (parameters.length > 2) {
                            command = 'l';
                            parameters.splice(0, 2);
                        }
                    }
                    if (ShapeMap[command]) {
                        ShapeMap[command](multiPath, {
                            parameters: parameters,
                            position: position,
                            isRelative: isRelative,
                            previousCommand: previousCommand
                        });
                        if (closePath && closePath.toLowerCase() === CLOSE) {
                            multiPath.close();
                        }
                    } else if (command !== MOVE) {
                        throw new Error('Error while parsing SVG path. Unsupported command: ' + command);
                    }
                    previousCommand = command;
                });
                return multiPath;
            }
        });
        PathParser.current = new PathParser();
        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, skipBaseHref) {
            var base = skipBaseHref ? '' : baseUrl();
            return 'url(' + base + '#' + id + ')';
        }
        var Node = BaseNode.extend({
            init: function (srcElement, options) {
                BaseNode.fn.init.call(this, srcElement);
                this.definitions = {};
                this.options = options;
            },
            destroy: function () {
                if (this.element) {
                    this.element._kendoNode = null;
                    this.element = null;
                }
                this.clearDefinitions();
                BaseNode.fn.destroy.call(this);
            },
            load: function (elements, pos) {
                var this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var srcElement = elements[i];
                    var children = srcElement.children;
                    var childNode = new NODE_MAP[srcElement.nodeType](srcElement, this$1.options);
                    if (defined(pos)) {
                        this$1.insertAt(childNode, pos);
                    } else {
                        this$1.append(childNode);
                    }
                    childNode.createDefinitions();
                    if (children && children.length > 0) {
                        childNode.load(children);
                    }
                    var element = this$1.element;
                    if (element) {
                        childNode.attachTo(element, pos);
                    }
                }
            },
            root: function () {
                var root = this;
                while (root.parent) {
                    root = root.parent;
                }
                return root;
            },
            attachTo: function (domElement, pos) {
                var container = document.createElement('div');
                renderSVG$1(container, '<svg xmlns=\'' + SVG_NS + '\' version=\'1.1\'>' + this.render() + '</svg>');
                var element = container.firstChild.firstChild;
                if (element) {
                    if (defined(pos)) {
                        domElement.insertBefore(element, domElement.childNodes[pos] || null);
                    } else {
                        domElement.appendChild(element);
                    }
                    this.setElement(element);
                }
            },
            setElement: function (element) {
                if (this.element) {
                    this.element._kendoNode = null;
                }
                this.element = element;
                this.element._kendoNode = this;
                var nodes = this.childNodes;
                for (var i = 0; i < nodes.length; i++) {
                    var childElement = element.childNodes[i];
                    nodes[i].setElement(childElement);
                }
            },
            clear: function () {
                this.clearDefinitions();
                if (this.element) {
                    this.element.innerHTML = '';
                }
                var children = this.childNodes;
                for (var i = 0; i < children.length; i++) {
                    children[i].destroy();
                }
                this.childNodes = [];
            },
            removeSelf: function () {
                if (this.element) {
                    var parentNode = this.element.parentNode;
                    if (parentNode) {
                        parentNode.removeChild(this.element);
                    }
                    this.element = null;
                }
                BaseNode.fn.removeSelf.call(this);
            },
            template: function () {
                return this.renderChildren();
            },
            render: function () {
                return this.template();
            },
            renderChildren: function () {
                var nodes = this.childNodes;
                var output = '';
                for (var i = 0; i < nodes.length; i++) {
                    output += nodes[i].render();
                }
                return output;
            },
            optionsChange: function (e) {
                var field = e.field;
                var value = e.value;
                if (field === 'visible') {
                    this.css('display', value ? '' : NONE);
                } else if (DefinitionMap[field] && isDefinition(field, value)) {
                    this.updateDefinition(field, value);
                } else if (field === 'opacity') {
                    this.attr('opacity', value);
                } else if (field === 'cursor') {
                    this.css('cursor', value);
                }
                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, this.refUrl(value.id));
                }
            },
            clearDefinitions: function () {
                var definitions = this.definitions;
                this.definitionChange({
                    action: 'remove',
                    definitions: definitions
                });
                this.definitions = {};
            },
            renderDefinitions: function () {
                return renderAllAttr(this.mapDefinitions());
            },
            mapDefinitions: function () {
                var this$1 = this;
                var definitions = this.definitions;
                var attrs = [];
                for (var field in definitions) {
                    attrs.push([
                        DefinitionMap[field],
                        this$1.refUrl(definitions[field].id)
                    ]);
                }
                return attrs;
            },
            refUrl: function (id) {
                var skipBaseHref = (this.options || {}).skipBaseHref;
                return refUrl(id, skipBaseHref);
            }
        });
        var GradientStopNode = Node.extend({
            template: function () {
                return '<stop ' + this.renderOffset() + ' ' + this.renderStyle() + ' />';
            },
            renderOffset: function () {
                return renderAttr('offset', this.srcElement.offset());
            },
            mapStyle: function () {
                var srcElement = this.srcElement;
                return [
                    [
                        'stop-color',
                        srcElement.color()
                    ],
                    [
                        'stop-opacity',
                        srcElement.opacity()
                    ]
                ];
            },
            optionsChange: function (e) {
                if (e.field === 'offset') {
                    this.attr(e.field, e.value);
                } else if (e.field === 'color' || e.field === 'opacity') {
                    this.css('stop-' + e.field, e.value);
                }
            }
        });
        var GradientNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this, srcElement);
                this.id = srcElement.id;
                this.loadStops();
            },
            loadStops: function () {
                var this$1 = this;
                var stops = this.srcElement.stops;
                var element = this.element;
                for (var idx = 0; idx < stops.length; idx++) {
                    var stopNode = new GradientStopNode(stops[idx]);
                    this$1.append(stopNode);
                    if (element) {
                        stopNode.attachTo(element);
                    }
                }
            },
            optionsChange: function (e) {
                if (e.field === 'gradient.stops') {
                    BaseNode.prototype.clear.call(this);
                    this.loadStops();
                } else if (e.field === 'gradient') {
                    this.allAttr(this.mapCoordinates());
                }
            },
            renderCoordinates: function () {
                return renderAllAttr(this.mapCoordinates());
            },
            mapSpace: function () {
                return [
                    'gradientUnits',
                    this.srcElement.userSpace() ? 'userSpaceOnUse' : 'objectBoundingBox'
                ];
            }
        });
        var LinearGradientNode = GradientNode.extend({
            template: function () {
                return '<linearGradient id=\'' + this.id + '\' ' + this.renderCoordinates() + '>' + this.renderChildren() + '</linearGradient>';
            },
            mapCoordinates: function () {
                var srcElement = this.srcElement;
                var start = srcElement.start();
                var end = srcElement.end();
                var attrs = [
                    [
                        'x1',
                        start.x
                    ],
                    [
                        'y1',
                        start.y
                    ],
                    [
                        'x2',
                        end.x
                    ],
                    [
                        'y2',
                        end.y
                    ],
                    this.mapSpace()
                ];
                return attrs;
            }
        });
        var RadialGradientNode = GradientNode.extend({
            template: function () {
                return '<radialGradient id=\'' + this.id + '\' ' + this.renderCoordinates() + '>' + this.renderChildren() + '</radialGradient>';
            },
            mapCoordinates: function () {
                var srcElement = this.srcElement;
                var center = srcElement.center();
                var radius = srcElement.radius();
                var attrs = [
                    [
                        'cx',
                        center.x
                    ],
                    [
                        'cy',
                        center.y
                    ],
                    [
                        'r',
                        radius
                    ],
                    this.mapSpace()
                ];
                return attrs;
            }
        });
        var ClipNode = Node.extend({
            init: function (srcElement) {
                Node.fn.init.call(this);
                this.srcElement = srcElement;
                this.id = srcElement.id;
                this.load([srcElement]);
            },
            template: function () {
                return '<clipPath id=\'' + this.id + '\'>' + this.renderChildren() + '</clipPath>';
            }
        });
        var DefinitionNode = Node.extend({
            init: function () {
                Node.fn.init.call(this);
                this.definitionMap = {};
            },
            attachTo: function (domElement) {
                this.element = domElement;
            },
            template: function () {
                return '<defs>' + this.renderChildren() + '</defs>';
            },
            definitionChange: function (e) {
                var definitions = e.definitions;
                var action = e.action;
                if (action === 'add') {
                    this.addDefinitions(definitions);
                } else if (action === 'remove') {
                    this.removeDefinitions(definitions);
                }
            },
            createDefinition: function (type, item) {
                var nodeType;
                if (type === 'clip') {
                    nodeType = ClipNode;
                } else if (type === 'fill') {
                    if (item instanceof LinearGradient) {
                        nodeType = LinearGradientNode;
                    } else if (item instanceof RadialGradient) {
                        nodeType = RadialGradientNode;
                    }
                }
                return new nodeType(item);
            },
            addDefinitions: function (definitions) {
                var this$1 = this;
                for (var field in definitions) {
                    this$1.addDefinition(field, definitions[field]);
                }
            },
            addDefinition: function (type, srcElement) {
                var ref = this;
                var element = ref.element;
                var definitionMap = ref.definitionMap;
                var id = srcElement.id;
                var mapItem = definitionMap[id];
                if (!mapItem) {
                    var node = this.createDefinition(type, srcElement);
                    definitionMap[id] = {
                        element: node,
                        count: 1
                    };
                    this.append(node);
                    if (element) {
                        node.attachTo(this.element);
                    }
                } else {
                    mapItem.count++;
                }
            },
            removeDefinitions: function (definitions) {
                var this$1 = this;
                for (var field in definitions) {
                    this$1.removeDefinition(definitions[field]);
                }
            },
            removeDefinition: function (srcElement) {
                var definitionMap = this.definitionMap;
                var id = srcElement.id;
                var mapItem = definitionMap[id];
                if (mapItem) {
                    mapItem.count--;
                    if (mapItem.count === 0) {
                        this.remove(this.childNodes.indexOf(mapItem.element), 1);
                        delete definitionMap[id];
                    }
                }
            }
        });
        var RootNode = Node.extend({
            init: function (options) {
                Node.fn.init.call(this);
                this.options = options;
                this.defs = new DefinitionNode();
            },
            attachTo: function (domElement) {
                this.element = domElement;
                this.defs.attachTo(domElement.firstElementChild);
            },
            clear: function () {
                BaseNode.prototype.clear.call(this);
            },
            template: function () {
                return this.defs.render() + this.renderChildren();
            },
            definitionChange: function (e) {
                this.defs.definitionChange(e);
            }
        });
        var RTL = 'rtl';
        function alignToScreen(element) {
            var ctm;
            try {
                ctm = element.getScreenCTM ? element.getScreenCTM() : null;
            } catch (e) {
            }
            if (ctm) {
                var left = -ctm.e % 1;
                var top = -ctm.f % 1;
                var style = element.style;
                if (left !== 0 || top !== 0) {
                    style.left = left + 'px';
                    style.top = top + 'px';
                }
            }
        }
        var Surface$1 = Surface.extend({
            init: function (element, options) {
                Surface.fn.init.call(this, element, options);
                this._root = new RootNode($.extend({ rtl: elementStyles(element, 'direction').direction === RTL }, this.options));
                renderSVG$1(this.element, this._template());
                this._rootElement = this.element.firstElementChild;
                alignToScreen(this._rootElement);
                this._root.attachTo(this._rootElement);
                bindEvents(this.element, {
                    click: this._click,
                    mouseover: this._mouseenter,
                    mouseout: this._mouseleave,
                    mousemove: this._mousemove
                });
                this.resize();
            },
            destroy: function () {
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                    this._rootElement = null;
                    unbindEvents(this.element, {
                        click: this._click,
                        mouseover: this._mouseenter,
                        mouseout: this._mouseleave,
                        mousemove: this._mousemove
                    });
                }
                Surface.fn.destroy.call(this);
            },
            translate: function (offset) {
                var viewBox = Math.round(offset.x) + ' ' + Math.round(offset.y) + ' ' + this._size.width + ' ' + this._size.height;
                this._offset = offset;
                this._rootElement.setAttribute('viewBox', viewBox);
            },
            draw: function (element) {
                Surface.fn.draw.call(this, element);
                this._root.load([element]);
            },
            clear: function () {
                Surface.fn.clear.call(this);
                this._root.clear();
            },
            svg: function () {
                return '<?xml version=\'1.0\' ?>' + this._template();
            },
            exportVisual: function () {
                var ref = this;
                var visual = ref._visual;
                var offset = ref._offset;
                if (offset) {
                    var wrap = new Group();
                    wrap.children.push(visual);
                    wrap.transform(transform().translate(-offset.x, -offset.y));
                    visual = wrap;
                }
                return visual;
            },
            _resize: function () {
                if (this._offset) {
                    this.translate(this._offset);
                }
            },
            _template: function () {
                return '<svg style=\'width: 100%; height: 100%; overflow: hidden;\' xmlns=\'' + SVG_NS + '\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' version=\'1.1\'>' + this._root.render() + '</svg>';
            }
        });
        Surface$1.prototype.type = 'svg';
        if (typeof document !== 'undefined' && document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#BasicStructure', '1.1')) {
            Surface.support.svg = true;
            SurfaceFactory.current.register('svg', Surface$1, 10);
        }
        var GroupNode = Node.extend({
            template: function () {
                return '<g' + (this.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;
            },
            renderTextAnchor: function () {
                var anchor;
                if ((this.options || {}).rtl) {
                    anchor = 'end';
                }
                return renderAttr('text-anchor', anchor);
            },
            template: function () {
                return '<text ' + this.renderTextAnchor() + ' ' + this.renderStyle() + ' ' + this.renderOpacity() + ' x=\'' + this.pos().x + '\' y=\'' + this.pos().y + '\'' + this.renderStroke() + ' ' + this.renderTransform() + ' ' + this.renderDefinitions() + this.renderFill() + '>' + this.renderContent() + '</text>';
            }
        });
        NODE_MAP.Text = TextNode;
        var MultiPathNode = PathNode.extend({
            renderData: function () {
                var this$1 = this;
                var paths = this.srcElement.paths;
                if (paths.length > 0) {
                    var result = [];
                    for (var i = 0; i < paths.length; i++) {
                        result.push(this$1.printPath(paths[i]));
                    }
                    return result.join(' ');
                }
            }
        });
        NODE_MAP.MultiPath = MultiPathNode;
        var geometry = {
            Circle: Circle$2,
            Arc: Arc$2,
            Rect: Rect,
            Point: Point,
            Segment: Segment,
            Matrix: Matrix,
            Size: Size,
            toMatrix: toMatrix,
            Transformation: Transformation,
            transform: transform
        };
        function exportGroup(group) {
            var root = new RootNode({ skipBaseHref: true });
            var bbox = group.clippedBBox();
            var rootGroup = group;
            if (bbox) {
                var origin = bbox.getOrigin();
                var exportRoot = new Group();
                exportRoot.transform(transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                rootGroup = exportRoot;
            }
            root.load([rootGroup]);
            var svg = '<?xml version=\'1.0\' ?><svg xmlns=\'' + SVG_NS + '\' xmlns:xlink=\'http://www.w3.org/1999/xlink\' version=\'1.1\'>' + root.render() + '</svg>';
            root.destroy();
            return svg;
        }
        var svg = {
            Surface: Surface$1,
            RootNode: RootNode,
            Node: Node,
            GroupNode: GroupNode,
            ArcNode: ArcNode,
            CircleNode: CircleNode,
            RectNode: RectNode,
            ImageNode: ImageNode,
            TextNode: TextNode,
            PathNode: PathNode,
            MultiPathNode: MultiPathNode,
            DefinitionNode: DefinitionNode,
            ClipNode: ClipNode,
            GradientStopNode: GradientStopNode,
            LinearGradientNode: LinearGradientNode,
            RadialGradientNode: RadialGradientNode,
            exportGroup: exportGroup
        };
        var NODE_MAP$2 = {};
        function renderPath(ctx, path) {
            var segments = path.segments;
            if (segments.length === 0) {
                return;
            }
            var segment = segments[0];
            var anchor = segment.anchor();
            ctx.moveTo(anchor.x, anchor.y);
            for (var i = 1; i < segments.length; i++) {
                segment = segments[i];
                anchor = segment.anchor();
                var prevSeg = segments[i - 1];
                var prevOut = prevSeg.controlOut();
                var controlIn = segment.controlIn();
                if (prevOut && controlIn) {
                    ctx.bezierCurveTo(prevOut.x, prevOut.y, controlIn.x, controlIn.y, anchor.x, anchor.y);
                } else {
                    ctx.lineTo(anchor.x, anchor.y);
                }
            }
            if (path.options.closed) {
                ctx.closePath();
            }
        }
        var Node$2 = BaseNode.extend({
            init: function (srcElement) {
                BaseNode.fn.init.call(this, srcElement);
                if (srcElement) {
                    this.initClip();
                }
            },
            initClip: function () {
                var clip = this.srcElement.clip();
                if (clip) {
                    this.clip = clip;
                    clip.addObserver(this);
                }
            },
            clear: function () {
                if (this.srcElement) {
                    this.srcElement.removeObserver(this);
                }
                this.clearClip();
                BaseNode.fn.clear.call(this);
            },
            clearClip: function () {
                if (this.clip) {
                    this.clip.removeObserver(this);
                    delete this.clip;
                }
            },
            setClip: function (ctx) {
                if (this.clip) {
                    ctx.beginPath();
                    renderPath(ctx, this.clip);
                    ctx.clip();
                }
            },
            optionsChange: function (e) {
                if (e.field === 'clip') {
                    this.clearClip();
                    this.initClip();
                }
                BaseNode.fn.optionsChange.call(this, e);
            },
            setTransform: function (ctx) {
                if (this.srcElement) {
                    var transform = this.srcElement.transform();
                    if (transform) {
                        ctx.transform.apply(ctx, transform.matrix().toArray(6));
                    }
                }
            },
            loadElements: function (elements, pos, cors) {
                var this$1 = this;
                for (var i = 0; i < elements.length; i++) {
                    var srcElement = elements[i];
                    var children = srcElement.children;
                    var childNode = new NODE_MAP$2[srcElement.nodeType](srcElement, cors);
                    if (children && children.length > 0) {
                        childNode.load(children, pos, cors);
                    }
                    if (defined(pos)) {
                        this$1.insertAt(childNode, pos);
                    } else {
                        this$1.append(childNode);
                    }
                }
            },
            load: function (elements, pos, cors) {
                this.loadElements(elements, pos, cors);
                this.invalidate();
            },
            setOpacity: function (ctx) {
                if (this.srcElement) {
                    var opacity = this.srcElement.opacity();
                    if (defined(opacity)) {
                        this.globalAlpha(ctx, opacity);
                    }
                }
            },
            globalAlpha: function (ctx, value) {
                var opactity = value;
                if (opactity && ctx.globalAlpha) {
                    opactity *= ctx.globalAlpha;
                }
                ctx.globalAlpha = opactity;
            },
            visible: function () {
                var src = this.srcElement;
                return !src || src && src.options.visible !== false;
            }
        });
        var GroupNode$2 = Node$2.extend({
            renderTo: function (ctx) {
                if (!this.visible()) {
                    return;
                }
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                var childNodes = this.childNodes;
                for (var i = 0; i < childNodes.length; i++) {
                    var child = childNodes[i];
                    if (child.visible()) {
                        child.renderTo(ctx);
                    }
                }
                ctx.restore();
            }
        });
        Traversable.extend(GroupNode$2.prototype, 'childNodes');
        NODE_MAP$2.Group = GroupNode$2;
        var FRAME_DELAY = 1000 / 60;
        var RootNode$2 = GroupNode$2.extend({
            init: function (canvas) {
                GroupNode$2.fn.init.call(this);
                this.canvas = canvas;
                this.ctx = canvas.getContext('2d');
                var invalidateHandler = this._invalidate.bind(this);
                this.invalidate = kendo.throttle(function () {
                    kendo.animationFrame(invalidateHandler);
                }, FRAME_DELAY);
            },
            destroy: function () {
                GroupNode$2.fn.destroy.call(this);
                this.canvas = null;
                this.ctx = null;
            },
            load: function (elements, pos, cors) {
                this.loadElements(elements, pos, cors);
                this._invalidate();
            },
            _invalidate: function () {
                if (!this.ctx) {
                    return;
                }
                this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                this.renderTo(this.ctx);
            }
        });
        Traversable.extend(RootNode$2.prototype, 'childNodes');
        var QuadRoot = Class.extend({
            init: function () {
                this.shapes = [];
            },
            _add: function (shape, bbox) {
                this.shapes.push({
                    bbox: bbox,
                    shape: shape
                });
                shape._quadNode = this;
            },
            pointShapes: function (point) {
                var shapes = this.shapes;
                var length = shapes.length;
                var result = [];
                for (var idx = 0; idx < length; idx++) {
                    if (shapes[idx].bbox.containsPoint(point)) {
                        result.push(shapes[idx].shape);
                    }
                }
                return result;
            },
            insert: function (shape, bbox) {
                this._add(shape, bbox);
            },
            remove: function (shape) {
                var shapes = this.shapes;
                var length = shapes.length;
                for (var idx = 0; idx < length; idx++) {
                    if (shapes[idx].shape === shape) {
                        shapes.splice(idx, 1);
                        break;
                    }
                }
            }
        });
        var QuadNode = QuadRoot.extend({
            init: function (rect) {
                QuadRoot.fn.init.call(this);
                this.children = [];
                this.rect = rect;
            },
            inBounds: function (rect) {
                var nodeRect = this.rect;
                var nodeBottomRight = nodeRect.bottomRight();
                var bottomRight = rect.bottomRight();
                var inBounds = nodeRect.origin.x <= rect.origin.x && nodeRect.origin.y <= rect.origin.y && bottomRight.x <= nodeBottomRight.x && bottomRight.y <= nodeBottomRight.y;
                return inBounds;
            },
            pointShapes: function (point) {
                var children = this.children;
                var length = children.length;
                var result = QuadRoot.fn.pointShapes.call(this, point);
                for (var idx = 0; idx < length; idx++) {
                    append(result, children[idx].pointShapes(point));
                }
                return result;
            },
            insert: function (shape, bbox) {
                var children = this.children;
                var inserted = false;
                if (this.inBounds(bbox)) {
                    if (this.shapes.length < 4) {
                        this._add(shape, bbox);
                    } else {
                        if (!children.length) {
                            this._initChildren();
                        }
                        for (var idx = 0; idx < children.length; idx++) {
                            if (children[idx].insert(shape, bbox)) {
                                inserted = true;
                                break;
                            }
                        }
                        if (!inserted) {
                            this._add(shape, bbox);
                        }
                    }
                    inserted = true;
                }
                return inserted;
            },
            _initChildren: function () {
                var ref = this;
                var rect = ref.rect;
                var children = ref.children;
                var center = rect.center();
                var halfWidth = rect.width() / 2;
                var halfHeight = rect.height() / 2;
                children.push(new QuadNode(new Rect([
                    rect.origin.x,
                    rect.origin.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    center.x,
                    rect.origin.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    rect.origin.x,
                    center.y
                ], [
                    halfWidth,
                    halfHeight
                ])), new QuadNode(new Rect([
                    center.x,
                    center.y
                ], [
                    halfWidth,
                    halfHeight
                ])));
            }
        });
        var ROOT_SIZE = 3000;
        var LEVEL_STEP = 10000;
        var MAX_LEVEL = 75;
        var ShapesQuadTree = Class.extend({
            init: function () {
                this.initRoots();
            },
            initRoots: function () {
                this.rootMap = {};
                this.root = new QuadRoot();
                this.rootElements = [];
            },
            clear: function () {
                var this$1 = this;
                var rootElements = this.rootElements;
                for (var idx = 0; idx < rootElements.length; idx++) {
                    this$1.remove(rootElements[idx]);
                }
                this.initRoots();
            },
            pointShape: function (point) {
                var sectorRoot = (this.rootMap[Math.floor(point.x / ROOT_SIZE)] || {})[Math.floor(point.y / ROOT_SIZE)];
                var result = this.root.pointShapes(point);
                if (sectorRoot) {
                    result = result.concat(sectorRoot.pointShapes(point));
                }
                this.assignZindex(result);
                result.sort(zIndexComparer);
                for (var idx = 0; idx < result.length; idx++) {
                    if (result[idx].containsPoint(point)) {
                        return result[idx];
                    }
                }
            },
            assignZindex: function (elements) {
                var this$1 = this;
                for (var idx = 0; idx < elements.length; idx++) {
                    var element = elements[idx];
                    var zIndex = 0;
                    var levelWeight = Math.pow(LEVEL_STEP, MAX_LEVEL);
                    var parents = [];
                    while (element) {
                        parents.push(element);
                        element = element.parent;
                    }
                    while (parents.length) {
                        element = parents.pop();
                        zIndex += ((element.parent ? element.parent.children : this$1.rootElements).indexOf(element) + 1) * levelWeight;
                        levelWeight /= LEVEL_STEP;
                    }
                    elements[idx]._zIndex = zIndex;
                }
            },
            optionsChange: function (e) {
                if (e.field === 'transform' || e.field === 'stroke.width') {
                    this.bboxChange(e.element);
                }
            },
            geometryChange: function (e) {
                this.bboxChange(e.element);
            },
            bboxChange: function (element) {
                var this$1 = this;
                if (element.nodeType === 'Group') {
                    for (var idx = 0; idx < element.children.length; idx++) {
                        this$1.bboxChange(element.children[idx]);
                    }
                } else {
                    if (element._quadNode) {
                        element._quadNode.remove(element);
                    }
                    this._insertShape(element);
                }
            },
            add: function (elements) {
                var elementsArray = Array.isArray(elements) ? elements.slice(0) : [elements];
                append(this.rootElements, elementsArray);
                this._insert(elementsArray);
            },
            childrenChange: function (e) {
                var this$1 = this;
                if (e.action === 'remove') {
                    for (var idx = 0; idx < e.items.length; idx++) {
                        this$1.remove(e.items[idx]);
                    }
                } else {
                    this._insert(Array.prototype.slice.call(e.items, 0));
                }
            },
            _insert: function (elements) {
                var this$1 = this;
                var element;
                while (elements.length > 0) {
                    element = elements.pop();
                    element.addObserver(this$1);
                    if (element.nodeType === 'Group') {
                        append(elements, element.children);
                    } else {
                        this$1._insertShape(element);
                    }
                }
            },
            _insertShape: function (shape) {
                var bbox = shape.bbox();
                if (bbox) {
                    var sectors = this.getSectors(bbox);
                    var x = sectors[0][0];
                    var y = sectors[1][0];
                    if (this.inRoot(sectors)) {
                        this.root.insert(shape, bbox);
                    } else {
                        var rootMap = this.rootMap;
                        if (!rootMap[x]) {
                            rootMap[x] = {};
                        }
                        if (!rootMap[x][y]) {
                            rootMap[x][y] = new QuadNode(new Rect([
                                x * ROOT_SIZE,
                                y * ROOT_SIZE
                            ], [
                                ROOT_SIZE,
                                ROOT_SIZE
                            ]));
                        }
                        rootMap[x][y].insert(shape, bbox);
                    }
                }
            },
            remove: function (element) {
                var this$1 = this;
                element.removeObserver(this);
                if (element.nodeType === 'Group') {
                    var children = element.children;
                    for (var idx = 0; idx < children.length; idx++) {
                        this$1.remove(children[idx]);
                    }
                } else if (element._quadNode) {
                    element._quadNode.remove(element);
                    delete element._quadNode;
                }
            },
            inRoot: function (sectors) {
                return sectors[0].length > 1 || sectors[1].length > 1;
            },
            getSectors: function (rect) {
                var bottomRight = rect.bottomRight();
                var bottomX = Math.floor(bottomRight.x / ROOT_SIZE);
                var bottomY = Math.floor(bottomRight.y / ROOT_SIZE);
                var sectors = [
                    [],
                    []
                ];
                for (var x = Math.floor(rect.origin.x / ROOT_SIZE); x <= bottomX; x++) {
                    sectors[0].push(x);
                }
                for (var y = Math.floor(rect.origin.y / ROOT_SIZE); y <= bottomY; y++) {
                    sectors[1].push(y);
                }
                return sectors;
            }
        });
        function zIndexComparer(x1, x2) {
            if (x1._zIndex < x2._zIndex) {
                return 1;
            }
            if (x1._zIndex > x2._zIndex) {
                return -1;
            }
            return 0;
        }
        var SurfaceCursor = Class.extend({
            init: function (surface) {
                surface.bind('mouseenter', this._mouseenter.bind(this));
                surface.bind('mouseleave', this._mouseleave.bind(this));
                this.element = surface.element;
            },
            clear: function () {
                this._resetCursor();
            },
            destroy: function () {
                this._resetCursor();
                delete this.element;
            },
            _mouseenter: function (e) {
                var cursor = this._shapeCursor(e);
                if (!cursor) {
                    this._resetCursor();
                } else {
                    if (!this._current) {
                        this._defaultCursor = this._getCursor();
                    }
                    this._setCursor(cursor);
                }
            },
            _mouseleave: function () {
                this._resetCursor();
            },
            _shapeCursor: function (e) {
                var shape = e.element;
                while (shape && !defined(shape.options.cursor)) {
                    shape = shape.parent;
                }
                if (shape) {
                    return shape.options.cursor;
                }
            },
            _getCursor: function () {
                if (this.element) {
                    return this.element.style.cursor;
                }
            },
            _setCursor: function (cursor) {
                if (this.element) {
                    this.element.style.cursor = cursor;
                    this._current = cursor;
                }
            },
            _resetCursor: function () {
                if (this._current) {
                    this._setCursor(this._defaultCursor || '');
                    delete this._current;
                }
            }
        });
        var Surface$3 = Surface.extend({
            init: function (element, options) {
                Surface.fn.init.call(this, element, options);
                this.element.innerHTML = this._template(this);
                var canvas = this.element.firstElementChild;
                var size = elementSize(element);
                canvas.width = size.width;
                canvas.height = size.height;
                this._rootElement = canvas;
                this._root = new RootNode$2(canvas);
                this._mouseTrackHandler = this._trackMouse.bind(this);
                bindEvents(this.element, {
                    click: this._mouseTrackHandler,
                    mousemove: this._mouseTrackHandler
                });
            },
            destroy: function () {
                Surface.fn.destroy.call(this);
                if (this._root) {
                    this._root.destroy();
                    this._root = null;
                }
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
                if (this._cursor) {
                    this._cursor.destroy();
                    delete this._cursor;
                }
                unbindEvents(this.element, {
                    click: this._mouseTrackHandler,
                    mousemove: this._mouseTrackHandler
                });
            },
            draw: function (element) {
                Surface.fn.draw.call(this, element);
                this._root.load([element], undefined, this.options.cors);
                if (this._searchTree) {
                    this._searchTree.add([element]);
                }
            },
            clear: function () {
                Surface.fn.clear.call(this);
                this._root.clear();
                if (this._searchTree) {
                    this._searchTree.clear();
                }
                if (this._cursor) {
                    this._cursor.clear();
                }
            },
            eventTarget: function (e) {
                if (this._searchTree) {
                    var point = this._surfacePoint(e);
                    var shape = this._searchTree.pointShape(point);
                    return shape;
                }
            },
            image: function () {
                var ref = this;
                var root = ref._root;
                var rootElement = ref._rootElement;
                var loadingStates = [];
                root.traverse(function (childNode) {
                    if (childNode.loading) {
                        loadingStates.push(childNode.loading);
                    }
                });
                var promise = createPromise();
                var resolveDataURL = function () {
                    root._invalidate();
                    try {
                        var data = rootElement.toDataURL();
                        promise.resolve(data);
                    } catch (e) {
                        promise.reject(e);
                    }
                };
                promiseAll(loadingStates).then(resolveDataURL, resolveDataURL);
                return promise;
            },
            suspendTracking: function () {
                Surface.fn.suspendTracking.call(this);
                if (this._searchTree) {
                    this._searchTree.clear();
                    delete this._searchTree;
                }
            },
            resumeTracking: function () {
                Surface.fn.resumeTracking.call(this);
                if (!this._searchTree) {
                    this._searchTree = new ShapesQuadTree();
                    var childNodes = this._root.childNodes;
                    var rootElements = [];
                    for (var idx = 0; idx < childNodes.length; idx++) {
                        rootElements.push(childNodes[idx].srcElement);
                    }
                    this._searchTree.add(rootElements);
                }
            },
            _resize: function () {
                this._rootElement.width = this._size.width;
                this._rootElement.height = this._size.height;
                this._root.invalidate();
            },
            _template: function () {
                return '<canvas style=\'width: 100%; height: 100%;\'></canvas>';
            },
            _enableTracking: function () {
                this._searchTree = new ShapesQuadTree();
                this._cursor = new SurfaceCursor(this);
                Surface.fn._enableTracking.call(this);
            },
            _trackMouse: function (e) {
                if (this._suspendedTracking) {
                    return;
                }
                var shape = this.eventTarget(e);
                if (e.type !== 'click') {
                    var currentShape = this._currentShape;
                    if (currentShape && currentShape !== shape) {
                        this.trigger('mouseleave', {
                            element: currentShape,
                            originalEvent: e,
                            type: 'mouseleave'
                        });
                    }
                    if (shape && currentShape !== shape) {
                        this.trigger('mouseenter', {
                            element: shape,
                            originalEvent: e,
                            type: 'mouseenter'
                        });
                    }
                    this.trigger('mousemove', {
                        element: shape,
                        originalEvent: e,
                        type: 'mousemove'
                    });
                    this._currentShape = shape;
                } else if (shape) {
                    this.trigger('click', {
                        element: shape,
                        originalEvent: e,
                        type: 'click'
                    });
                }
            }
        });
        Surface$3.prototype.type = 'canvas';
        if (typeof document !== 'undefined' && document.createElement('canvas').getContext) {
            Surface.support.canvas = true;
            SurfaceFactory.current.register('canvas', Surface$3, 20);
        }
        function addGradientStops(gradient, stops) {
            for (var idx = 0; idx < stops.length; idx++) {
                var stop = stops[idx];
                var color = kendo.parseColor(stop.color());
                color.a *= stop.opacity();
                gradient.addColorStop(stop.offset(), color.toCssRgba());
            }
        }
        var PathNode$2 = Node$2.extend({
            renderTo: function (ctx) {
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                ctx.beginPath();
                this.renderPoints(ctx, this.srcElement);
                this.setLineDash(ctx);
                this.setLineCap(ctx);
                this.setLineJoin(ctx);
                this.setFill(ctx);
                this.setStroke(ctx);
                ctx.restore();
            },
            setFill: function (ctx) {
                var fill = this.srcElement.options.fill;
                var hasFill = false;
                if (fill) {
                    if (fill.nodeType === 'Gradient') {
                        this.setGradientFill(ctx, fill);
                        hasFill = true;
                    } else if (!isTransparent(fill.color)) {
                        ctx.fillStyle = fill.color;
                        ctx.save();
                        this.globalAlpha(ctx, fill.opacity);
                        ctx.fill();
                        ctx.restore();
                        hasFill = true;
                    }
                }
                return hasFill;
            },
            setGradientFill: function (ctx, fill) {
                var bbox = this.srcElement.rawBBox();
                var gradient;
                if (fill instanceof LinearGradient) {
                    var start = fill.start();
                    var end = fill.end();
                    gradient = ctx.createLinearGradient(start.x, start.y, end.x, end.y);
                } else if (fill instanceof RadialGradient) {
                    var center = fill.center();
                    gradient = ctx.createRadialGradient(center.x, center.y, 0, center.x, center.y, fill.radius());
                }
                addGradientStops(gradient, fill.stops);
                ctx.save();
                if (!fill.userSpace()) {
                    ctx.transform(bbox.width(), 0, 0, bbox.height(), bbox.origin.x, bbox.origin.y);
                }
                ctx.fillStyle = gradient;
                ctx.fill();
                ctx.restore();
            },
            setStroke: function (ctx) {
                var stroke = this.srcElement.options.stroke;
                if (stroke && !isTransparent(stroke.color) && stroke.width > 0) {
                    ctx.strokeStyle = stroke.color;
                    ctx.lineWidth = valueOrDefault(stroke.width, 1);
                    ctx.save();
                    this.globalAlpha(ctx, stroke.opacity);
                    ctx.stroke();
                    ctx.restore();
                    return true;
                }
            },
            dashType: function () {
                var stroke = this.srcElement.options.stroke;
                if (stroke && stroke.dashType) {
                    return stroke.dashType.toLowerCase();
                }
            },
            setLineDash: function (ctx) {
                var dashType = this.dashType();
                if (dashType && dashType !== SOLID) {
                    var dashArray = DASH_ARRAYS[dashType];
                    if (ctx.setLineDash) {
                        ctx.setLineDash(dashArray);
                    } else {
                        ctx.mozDash = dashArray;
                        ctx.webkitLineDash = dashArray;
                    }
                }
            },
            setLineCap: function (ctx) {
                var dashType = this.dashType();
                var stroke = this.srcElement.options.stroke;
                if (dashType && dashType !== SOLID) {
                    ctx.lineCap = BUTT;
                } else if (stroke && stroke.lineCap) {
                    ctx.lineCap = stroke.lineCap;
                }
            },
            setLineJoin: function (ctx) {
                var stroke = this.srcElement.options.stroke;
                if (stroke && stroke.lineJoin) {
                    ctx.lineJoin = stroke.lineJoin;
                }
            },
            renderPoints: function (ctx, path) {
                renderPath(ctx, path);
            }
        });
        NODE_MAP$2.Path = PathNode$2;
        var ArcNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var path = this.srcElement.toPath();
                renderPath(ctx, path);
            }
        });
        NODE_MAP$2.Arc = ArcNode$2;
        var CircleNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var ref = this.srcElement.geometry();
                var center = ref.center;
                var radius = ref.radius;
                ctx.arc(center.x, center.y, radius, 0, Math.PI * 2);
            }
        });
        NODE_MAP$2.Circle = CircleNode$2;
        var RectNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var ref = this.srcElement.geometry();
                var origin = ref.origin;
                var size = ref.size;
                ctx.rect(origin.x, origin.y, size.width, size.height);
            }
        });
        NODE_MAP$2.Rect = RectNode$2;
        var ImageNode$2 = PathNode$2.extend({
            init: function (srcElement, cors) {
                PathNode$2.fn.init.call(this, srcElement);
                this.onLoad = this.onLoad.bind(this);
                this.onError = this.onError.bind(this);
                this.loading = createPromise();
                var img = this.img = new Image();
                if (cors && !/^data:/i.test(srcElement.src())) {
                    img.crossOrigin = cors;
                }
                img.src = srcElement.src();
                if (img.complete) {
                    this.onLoad();
                } else {
                    img.onload = this.onLoad;
                    img.onerror = this.onError;
                }
            },
            renderTo: function (ctx) {
                if (this.loading.state() === 'resolved') {
                    ctx.save();
                    this.setTransform(ctx);
                    this.setClip(ctx);
                    this.drawImage(ctx);
                    ctx.restore();
                }
            },
            optionsChange: function (e) {
                if (e.field === 'src') {
                    this.loading = createPromise();
                    this.img.src = this.srcElement.src();
                } else {
                    PathNode$2.fn.optionsChange.call(this, e);
                }
            },
            onLoad: function () {
                this.loading.resolve();
                this.invalidate();
            },
            onError: function () {
                this.loading.reject(new Error('Unable to load image \'' + this.img.src + '\'. Check for connectivity and verify CORS headers.'));
            },
            drawImage: function (ctx) {
                var rect = this.srcElement.rect();
                var topLeft = rect.topLeft();
                ctx.drawImage(this.img, topLeft.x, topLeft.y, rect.width(), rect.height());
            }
        });
        NODE_MAP$2.Image = ImageNode$2;
        var TextNode$2 = PathNode$2.extend({
            renderTo: function (ctx) {
                var text = this.srcElement;
                var pos = text.position();
                var size = text.measure();
                ctx.save();
                this.setTransform(ctx);
                this.setClip(ctx);
                this.setOpacity(ctx);
                ctx.beginPath();
                ctx.font = text.options.font;
                ctx.textAlign = 'left';
                if (this.setFill(ctx)) {
                    ctx.fillText(text.content(), pos.x, pos.y + size.baseline);
                }
                if (this.setStroke(ctx)) {
                    this.setLineDash(ctx);
                    ctx.strokeText(text.content(), pos.x, pos.y + size.baseline);
                }
                ctx.restore();
            }
        });
        NODE_MAP$2.Text = TextNode$2;
        var MultiPathNode$2 = PathNode$2.extend({
            renderPoints: function (ctx) {
                var paths = this.srcElement.paths;
                for (var i = 0; i < paths.length; i++) {
                    renderPath(ctx, paths[i]);
                }
            }
        });
        NODE_MAP$2.MultiPath = MultiPathNode$2;
        var canvas = {
            Surface: Surface$3,
            RootNode: RootNode$2,
            Node: Node$2,
            GroupNode: GroupNode$2,
            ArcNode: ArcNode$2,
            CircleNode: CircleNode$2,
            RectNode: RectNode$2,
            ImageNode: ImageNode$2,
            TextNode: TextNode$2,
            PathNode: PathNode$2,
            MultiPathNode: MultiPathNode$2
        };
        function exportImage(group, options) {
            var defaults = {
                width: '800px',
                height: '600px',
                cors: 'Anonymous'
            };
            var exportRoot = group;
            var bbox = group.clippedBBox();
            if (bbox) {
                var origin = bbox.getOrigin();
                exportRoot = new Group();
                exportRoot.transform(transform().translate(-origin.x, -origin.y));
                exportRoot.children.push(group);
                var size = bbox.getSize();
                defaults.width = size.width + 'px';
                defaults.height = size.height + 'px';
            }
            var surfaceOptions = $.extend(defaults, options);
            var container = document.createElement('div');
            var style = container.style;
            style.display = 'none';
            style.width = surfaceOptions.width;
            style.height = surfaceOptions.height;
            document.body.appendChild(container);
            var surface = new Surface$3(container, surfaceOptions);
            surface.suspendTracking();
            surface.draw(exportRoot);
            var promise = surface.image();
            var destroy = function () {
                surface.destroy();
                document.body.removeChild(container);
            };
            promise.then(destroy, destroy);
            return promise;
        }
        function exportSVG(group, options) {
            var svg = exportGroup(group);
            if (!options || !options.raw) {
                svg = 'data:image/svg+xml;base64,' + encodeBase64(svg);
            }
            return createPromise().resolve(svg);
        }
        var browser = 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.k-widget');
                        if (grid && grid.querySelector('.k-auto-scrollable')) {
                            gridHead = grid.querySelector('.k-grid-header');
                        }
                    }
                    var page = makePage();
                    var range = doc.createRange();
                    range.setStartBefore(copy);
                    range.setEndBefore(el);
                    page.appendChild(range.extractContents());
                    copy.parentNode.insertBefore(page, copy);
                    preventBulletOnListItem(el.parentNode);
                    if (table) {
                        table = closest(el, 'table');
                        if (options.repeatHeaders && thead) {
                            table.insertBefore(thead.cloneNode(true), table.firstChild);
                        }
                        if (colgroup) {
                            table.insertBefore(colgroup.cloneNode(true), table.firstChild);
                        }
                    }
                    if (options.repeatHeaders && gridHead) {
                        grid = closest(el, '.k-grid.k-widget');
                        grid.insertBefore(gridHead.cloneNode(true), grid.firstChild);
                    }
                }
                function makePage() {
                    var page = doc.createElement('KENDO-PDF-PAGE');
                    setCSS(page, {
                        display: 'block',
                        boxSizing: 'content-box',
                        width: pageWidth ? pageWidth + 'px' : 'auto',
                        padding: margin.top + 'px ' + margin.right + 'px ' + margin.bottom + 'px ' + margin.left + 'px',
                        position: 'relative',
                        height: pageHeight ? pageHeight + 'px' : 'auto',
                        overflow: pageHeight || pageWidth ? 'hidden' : 'visible',
                        clear: 'both'
                    });
                    if (options && options.pageClassName) {
                        page.className = options.pageClassName;
                    }
                    pages.push(page);
                    return page;
                }
                function fallsOnMargin(thing) {
                    var box = thing.getBoundingClientRect();
                    if (box.width === 0 || box.height === 0) {
                        return 0;
                    }
                    var top = copy.getBoundingClientRect().top;
                    var available = pageHeight - adjust;
                    return box.height > available ? 3 : box.top - top > available ? 1 : box.bottom - top > available ? 2 : 0;
                }
                function splitText(node, isFirst) {
                    if (!/\S/.test(node.data)) {
                        return;
                    }
                    var len = node.data.length;
                    var range = doc.createRange();
                    range.selectNodeContents(node);
                    var fall = fallsOnMargin(range);
                    if (!fall) {
                        return;
                    }
                    var nextnode = node;
                    if (fall == 1) {
                        if (isFirst) {
                            breakAtElement(node.parentNode);
                        } else {
                            breakAtElement(node);
                        }
                    } else {
                        (function findEOP(min, pos, max) {
                            range.setEnd(node, pos);
                            if (min == pos || pos == max) {
                                return pos;
                            }
                            if (fallsOnMargin(range)) {
                                return findEOP(min, min + pos >> 1, pos);
                            } else {
                                return findEOP(pos, pos + max >> 1, max);
                            }
                        }(0, len >> 1, len));
                        if (!/\S/.test(range.toString()) && isFirst) {
                            breakAtElement(node.parentNode);
                        } else {
                            nextnode = node.splitText(range.endOffset);
                            var page = makePage();
                            range.setStartBefore(copy);
                            page.appendChild(range.extractContents());
                            copy.parentNode.insertBefore(page, copy);
                            preventBulletOnListItem(nextnode.parentNode);
                        }
                    }
                    splitText(nextnode);
                }
                function preventBulletOnListItem(el) {
                    var li = closest(el, 'li');
                    if (li) {
                        li.setAttribute('kendo-no-bullet', '1');
                        preventBulletOnListItem(li.parentNode);
                    }
                }
            }
            return promise;
        }
        drawDOM.getFontFaces = getFontFaces;
        drawDOM.drawText = function (element) {
            var group = new Group();
            nodeInfo._clipbox = false;
            nodeInfo._matrix = Matrix.unit();
            nodeInfo._stackingContext = {
                element: element,
                group: group
            };
            pushNodeInfo(element, getComputedStyle(element), group);
            if (element.firstChild.nodeType == 3) {
                renderText(element, element.firstChild, group);
            } else {
                _renderElement(element, group);
            }
            popNodeInfo();
            return group;
        };
        var parseBackgroundImage = function () {
            var tok_linear_gradient = /^((-webkit-|-moz-|-o-|-ms-)?linear-gradient\s*)\(/;
            var tok_percent = /^([-0-9.]+%)/;
            var tok_length = /^([-0-9.]+px)/;
            var tok_keyword = /^(left|right|top|bottom|to|center)\W/;
            var tok_angle = /^([-0-9.]+(deg|grad|rad|turn))/;
            var tok_whitespace = /^(\s+)/;
            var tok_popen = /^(\()/;
            var tok_pclose = /^(\))/;
            var tok_comma = /^(,)/;
            var tok_url = /^(url)\(/;
            var tok_content = /^(.*?)\)/;
            var cache1 = {}, cache2 = {};
            function parse(input) {
                var orig = input;
                if (hasOwnProperty(cache1, orig)) {
                    return cache1[orig];
                }
                function skip_ws() {
                    var m = tok_whitespace.exec(input);
                    if (m) {
                        input = input.substr(m[1].length);
                    }
                }
                function read(token) {
                    skip_ws();
                    var m = token.exec(input);
                    if (m) {
                        input = input.substr(m[1].length);
                        return m[1];
                    }
                }
                function read_stop() {
                    var color = kendo.parseColor(input, true);
                    var length, percent;
                    if (color) {
                        var match = /^#[0-9a-f]+/i.exec(input) || /^rgba?\(.*?\)/i.exec(input) || /^..*?\b/.exec(input);
                        input = input.substr(match[0].length);
                        color = color.toRGB();
                        if (!(length = read(tok_length))) {
                            percent = read(tok_percent);
                        }
                        return {
                            color: color,
                            length: length,
                            percent: percent
                        };
                    }
                }
                function read_linear_gradient(propName) {
                    var angle;
                    var to1, to2;
                    var stops = [];
                    var reverse = false;
                    if (read(tok_popen)) {
                        angle = read(tok_angle);
                        if (angle) {
                            angle = parseAngle(angle);
                            read(tok_comma);
                        } else {
                            to1 = read(tok_keyword);
                            if (to1 == 'to') {
                                to1 = read(tok_keyword);
                            } else if (to1 && /^-/.test(propName)) {
                                reverse = true;
                            }
                            to2 = read(tok_keyword);
                            read(tok_comma);
                        }
                        if (/-moz-/.test(propName) && angle == null && to1 == null) {
                            var x = read(tok_percent), y = read(tok_percent);
                            reverse = true;
                            if (x == '0%') {
                                to1 = 'left';
                            } else if (x == '100%') {
                                to1 = 'right';
                            }
                            if (y == '0%') {
                                to2 = 'top';
                            } else if (y == '100%') {
                                to2 = 'bottom';
                            }
                            read(tok_comma);
                        }
                        while (input && !read(tok_pclose)) {
                            var stop = read_stop();
                            if (!stop) {
                                break;
                            }
                            stops.push(stop);
                            read(tok_comma);
                        }
                        return {
                            type: 'linear',
                            angle: angle,
                            to: to1 && to2 ? to1 + ' ' + to2 : to1 ? to1 : to2 ? to2 : null,
                            stops: stops,
                            reverse: reverse
                        };
                    }
                }
                function read_url() {
                    if (read(tok_popen)) {
                        var url = read(tok_content);
                        url = url.replace(/^['"]+|["']+$/g, '');
                        read(tok_pclose);
                        return {
                            type: 'url',
                            url: url
                        };
                    }
                }
                var tok;
                if (tok = read(tok_linear_gradient)) {
                    tok = read_linear_gradient(tok);
                } else if (tok = read(tok_url)) {
                    tok = read_url();
                }
                return cache1[orig] = tok || { type: 'none' };
            }
            return function (input) {
                if (hasOwnProperty(cache2, input)) {
                    return cache2[input];
                }
                return cache2[input] = splitProperty(input).map(parse);
            };
        }();
        var splitProperty = function () {
            var cache = {};
            return function (input, separator) {
                if (!separator) {
                    separator = /^\s*,\s*/;
                }
                var cacheKey = input + separator;
                if (hasOwnProperty(cache, cacheKey)) {
                    return cache[cacheKey];
                }
                var ret = [];
                var last$$1 = 0, pos = 0;
                var in_paren = 0;
                var in_string = false;
                var m;
                function looking_at(rx) {
                    return m = rx.exec(input.substr(pos));
                }
                function trim(str) {
                    return str.replace(/^\s+|\s+$/g, '');
                }
                while (pos < input.length) {
                    if (!in_string && looking_at(/^[\(\[\{]/)) {
                        in_paren++;
                        pos++;
                    } else if (!in_string && looking_at(/^[\)\]\}]/)) {
                        in_paren--;
                        pos++;
                    } else if (!in_string && looking_at(/^[\"\']/)) {
                        in_string = m[0];
                        pos++;
                    } else if (in_string == '\'' && looking_at(/^\\\'/)) {
                        pos += 2;
                    } else if (in_string == '"' && looking_at(/^\\\"/)) {
                        pos += 2;
                    } else if (in_string == '\'' && looking_at(/^\'/)) {
                        in_string = false;
                        pos++;
                    } else if (in_string == '"' && looking_at(/^\"/)) {
                        in_string = false;
                        pos++;
                    } else if (looking_at(separator)) {
                        if (!in_string && !in_paren && pos > last$$1) {
                            ret.push(trim(input.substring(last$$1, pos)));
                            last$$1 = pos + m[0].length;
                        }
                        pos += m[0].length;
                    } else {
                        pos++;
                    }
                }
                if (last$$1 < pos) {
                    ret.push(trim(input.substring(last$$1, pos)));
                }
                return cache[cacheKey] = ret;
            };
        }();
        var getFontURL = function (cache) {
            return function (el) {
                var url = cache[el];
                if (!url) {
                    var m;
                    if (m = /url\((['"]?)([^'")]*?)\1\)\s+format\((['"]?)truetype\3\)/.exec(el)) {
                        url = cache[el] = m[2];
                    } else if (m = /url\((['"]?)([^'")]*?\.ttf)\1\)/.exec(el)) {
                        url = cache[el] = m[2];
                    }
                }
                return url;
            };
        }(Object.create ? Object.create(null) : {});
        var getFontHeight = function (cache) {
            return function (font) {
                var height = cache[font];
                if (height == null) {
                    height = cache[font] = kendoUtil.measureText('Mapq', { font: font }).height;
                }
                return height;
            };
        }(Object.create ? Object.create(null) : {});
        function getFontFaces(doc) {
            if (doc == null) {
                doc = document;
            }
            var result = {};
            for (var i = 0; i < doc.styleSheets.length; ++i) {
                doStylesheet(doc.styleSheets[i]);
            }
            return result;
            function doStylesheet(ss) {
                if (ss) {
                    var rules = null;
                    try {
                        rules = ss.cssRules;
                    } catch (ex) {
                    }
                    if (rules) {
                        addRules(ss, rules);
                    }
                }
            }
            function findFonts(rule) {
                var src = getPropertyValue(rule.style, 'src');
                if (src) {
                    return splitProperty(src).reduce(function (a, el) {
                        var font = getFontURL(el);
                        if (font) {
                            a.push(font);
                        }
                        return a;
                    }, []);
                } else {
                    var font = getFontURL(rule.cssText);
                    return font ? [font] : [];
                }
            }
            function addRules(styleSheet, rules) {
                for (var i = 0; i < rules.length; ++i) {
                    var r = rules[i];
                    switch (r.type) {
                    case 3:
                        doStylesheet(r.styleSheet);
                        break;
                    case 5:
                        var style = r.style;
                        var family = splitProperty(getPropertyValue(style, 'font-family'));
                        var bold = /^([56789]00|bold)$/i.test(getPropertyValue(style, 'font-weight'));
                        var italic = 'italic' == getPropertyValue(style, 'font-style');
                        var src = findFonts(r);
                        if (src.length > 0) {
                            addRule(styleSheet, family, bold, italic, src[0]);
                        }
                    }
                }
            }
            function addRule(styleSheet, names, bold, italic, url) {
                if (!/^data:/i.test(url)) {
                    if (!(/^[^\/:]+:\/\//.test(url) || /^\//.test(url))) {
                        url = String(styleSheet.href).replace(/[^\/]*$/, '') + url;
                    }
                }
                names.forEach(function (name) {
                    name = name.replace(/^(['"]?)(.*?)\1$/, '$2');
                    if (bold) {
                        name += '|bold';
                    }
                    if (italic) {
                        name += '|italic';
                    }
                    result[name] = url;
                });
            }
        }
        function hasOwnProperty(obj, key) {
            return Object.prototype.hasOwnProperty.call(obj, key);
        }
        function getCounter(name) {
            name = '_counter_' + name;
            return nodeInfo[name];
        }
        function getAllCounters(name) {
            var values = [], p = nodeInfo;
            name = '_counter_' + name;
            while (p) {
                if (hasOwnProperty(p, name)) {
                    values.push(p[name]);
                }
                p = Object.getPrototypeOf(p);
            }
            return values.reverse();
        }
        function incCounter(name, inc) {
            var p = nodeInfo;
            name = '_counter_' + name;
            while (p && !hasOwnProperty(p, name)) {
                p = Object.getPrototypeOf(p);
            }
            if (!p) {
                p = nodeInfo._root;
            }
            p[name] = (p[name] || 0) + (inc == null ? 1 : inc);
        }
        function resetCounter(name, val) {
            name = '_counter_' + name;
            nodeInfo[name] = val == null ? 0 : val;
        }
        function doCounters(a, f, def) {
            for (var i = 0; i < a.length;) {
                var name = a[i++];
                var val = parseFloat(a[i]);
                if (isNaN(val)) {
                    f(name, def);
                } else {
                    f(name, val);
                    ++i;
                }
            }
        }
        function updateCounters(style) {
            var counterReset = getPropertyValue(style, 'counter-reset');
            if (counterReset) {
                doCounters(splitProperty(counterReset, /^\s+/), resetCounter, 0);
            }
            var counterIncrement = getPropertyValue(style, 'counter-increment');
            if (counterIncrement) {
                doCounters(splitProperty(counterIncrement, /^\s+/), incCounter, 1);
            }
        }
        function parseColor$1(str, css) {
            var color = kendo.parseColor(str, true);
            if (color) {
                color = color.toRGB();
                if (css) {
                    color = color.toCssRgba();
                } else if (color.a === 0) {
                    color = null;
                }
            }
            return color;
        }
        function whenImagesAreActuallyLoaded(elements, callback) {
            var pending = 0;
            elements.forEach(function (el) {
                var images = el.querySelectorAll('img');
                for (var i = 0; i < images.length; ++i) {
                    var img = images[i];
                    if (!img.complete) {
                        pending++;
                        img.onload = img.onerror = next;
                    }
                }
            });
            if (!pending) {
                next();
            }
            function next() {
                if (--pending <= 0) {
                    callback();
                }
            }
        }
        function cacheImages(element, callback) {
            var urls = [];
            function add(url) {
                if (!IMAGE_CACHE[url]) {
                    IMAGE_CACHE[url] = true;
                    urls.push(url);
                }
            }
            (function dive(element) {
                if (/^img$/i.test(element.tagName)) {
                    add(element.src);
                }
                parseBackgroundImage(getPropertyValue(getComputedStyle(element), 'background-image')).forEach(function (bg) {
                    if (bg.type == 'url') {
                        add(bg.url);
                    }
                });
                if (element.children) {
                    slice$1(element.children).forEach(dive);
                }
            }(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) {
                    var sign = options.isRtl ? -1 : 1;
                    viewportWidth -= sign * kendo.support.scrollbar();
                }
                siblingContainer = anchor.parents().filter(wrapper.siblings());
                if (siblingContainer[0]) {
                    parentZIndex = Math.max(Number(siblingContainer.css('zIndex')), 0);
                    if (parentZIndex) {
                        zIndex = parentZIndex + 10;
                    } else {
                        parents = anchor.parentsUntil(siblingContainer);
                        for (length = parents.length; idx < length; idx++) {
                            parentZIndex = Number($(parents[idx]).css('zIndex'));
                            if (parentZIndex && zIndex < parentZIndex) {
                                zIndex = parentZIndex + 10;
                            }
                        }
                    }
                }
                wrapper.css('zIndex', zIndex);
                if (fixed && fixed.isFixed) {
                    wrapper.css({
                        left: fixed.x,
                        top: fixed.y
                    });
                } else {
                    wrapper.css(that._align(origins, positions));
                }
                var pos = getOffset(wrapper, POSITION, anchor[0] === wrapper.offsetParent()[0]), offset = getOffset(wrapper), anchorParent = anchor.offsetParent().parent('.k-animation-container,.k-popup,.k-group');
                if (anchorParent.length) {
                    pos = getOffset(wrapper, POSITION, true);
                    offset = getOffset(wrapper);
                }
                offset.top -= viewportOffset.top;
                offset.left -= viewportOffset.left;
                if (!that.wrapper.data(LOCATION)) {
                    wrapper.data(LOCATION, extend({}, pos));
                }
                var offsets = extend({}, offset), location = extend({}, pos), adjustSize = options.adjustSize;
                if (collisions[0] === 'fit') {
                    location.top += that._fit(offsets.top, outerHeight(wrapper) + adjustSize.height, viewportHeight / zoomLevel);
                }
                if (collisions[1] === 'fit') {
                    location.left += that._fit(offsets.left, outerWidth(wrapper) + adjustSize.width, viewportWidth / zoomLevel);
                }
                var flipPos = extend({}, location);
                var elementHeight = outerHeight(element);
                var wrapperHeight = outerHeight(wrapper);
                if (!wrapper.height() && elementHeight) {
                    wrapperHeight = wrapperHeight + elementHeight;
                }
                if (collisions[0] === 'flip') {
                    location.top += that._flip(offsets.top, elementHeight, outerHeight(anchor), viewportHeight / zoomLevel, origins[0], positions[0], wrapperHeight);
                }
                if (collisions[1] === 'flip') {
                    location.left += that._flip(offsets.left, outerWidth(element), outerWidth(anchor), viewportWidth / zoomLevel, origins[1], positions[1], outerWidth(wrapper));
                }
                element.css(POSITION, ABSOLUTE);
                wrapper.css(location);
                return location.left != flipPos.left || location.top != flipPos.top;
            },
            _align: function (origin, position) {
                var that = this, element = that.wrapper, anchor = $(that.options.anchor), verticalOrigin = origin[0], horizontalOrigin = origin[1], verticalPosition = position[0], horizontalPosition = position[1], anchorOffset = getOffset(anchor), appendTo = $(that.options.appendTo), appendToOffset, width = outerWidth(element), height = outerHeight(element), 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: '<span class="k-widget k-tooltip k-tooltip-validation">' + '<span class="k-icon k-i-warning"> </span> #=message#</span>',
                messages: {
                    required: '{0} is required',
                    pattern: '{0} is not valid',
                    min: '{0} should be greater than or equal to {1}',
                    max: '{0} should be smaller than or equal to {1}',
                    step: '{0} is not valid',
                    email: '{0} is not valid email',
                    url: '{0} is not valid URL',
                    date: '{0} is not valid date',
                    dateCompare: 'End date should be greater than or equal to the start date'
                },
                rules: {
                    required: function (input) {
                        var checkbox = input.filter('[type=checkbox]').length && !input.is(':checked'), value = input.val();
                        return !(hasAttribute(input, 'required') && (!value || value === '' || value.length === 0 || checkbox));
                    },
                    pattern: function (input) {
                        if (input.filter('[type=text],[type=email],[type=url],[type=tel],[type=search],[type=password]').filter('[pattern]').length && input.val() !== '') {
                            return patternMatcher(input.val(), input.attr('pattern'));
                        }
                        return true;
                    },
                    min: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[min]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, val = kendo.parseFloat(input.val());
                            return min <= val;
                        }
                        return true;
                    },
                    max: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[max]').length && input.val() !== '') {
                            var max = parseFloat(input.attr('max')) || 0, val = kendo.parseFloat(input.val());
                            return max >= val;
                        }
                        return true;
                    },
                    step: function (input) {
                        if (input.filter(NUMBERINPUTSELECTOR + ',[' + kendo.attr('type') + '=number]').filter('[step]').length && input.val() !== '') {
                            var min = parseFloat(input.attr('min')) || 0, step = parseFloat(input.attr('step')) || 1, val = parseFloat(input.val()), decimals = numberOfDecimalDigits(step), raise;
                            if (decimals) {
                                raise = Math.pow(10, decimals);
                                return Math.floor((val - min) * raise) % (step * raise) / Math.pow(100, decimals) === 0;
                            }
                            return (val - min) % step === 0;
                        }
                        return true;
                    },
                    email: function (input) {
                        return matcher(input, '[type=email],[' + kendo.attr('type') + '=email]', emailRegExp);
                    },
                    url: function (input) {
                        return matcher(input, '[type=url],[' + kendo.attr('type') + '=url]', urlRegExp);
                    },
                    date: function (input) {
                        if (input.filter('[type^=date],[' + kendo.attr('type') + '=date]').length && input.val() !== '') {
                            return kendo.parseDate(input.val(), input.attr(kendo.attr('format'))) !== null;
                        }
                        return true;
                    }
                },
                validateOnBlur: true
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.element.off(NS);
            },
            value: function () {
                if (!this._isValidated) {
                    return false;
                }
                return this.errors().length === 0;
            },
            _submit: function (e) {
                if (!this.validate()) {
                    e.stopPropagation();
                    e.stopImmediatePropagation();
                    e.preventDefault();
                    return false;
                }
                return true;
            },
            _checkElement: function (element) {
                var state = this.value();
                this.validateInput(element);
                if (this.value() !== state) {
                    this.trigger(CHANGE);
                }
            },
            _attachEvents: function () {
                var that = this;
                if (that.element.is(FORM)) {
                    that.element.on('submit' + NS, proxy(that._submit, that));
                }
                if (that.options.validateOnBlur) {
                    if (!that.element.is(INPUTSELECTOR)) {
                        that.element.on(BLUR + NS, that._inputSelector, function () {
                            that._checkElement($(this));
                        });
                        that.element.on('click' + NS, that._checkboxSelector, function () {
                            that._checkElement($(this));
                        });
                    } else {
                        that.element.on(BLUR + NS, function () {
                            that._checkElement(that.element);
                        });
                        if (that.element.is(CHECKBOXSELECTOR)) {
                            that.element.on('click' + NS, function () {
                                that._checkElement(that.element);
                            });
                        }
                    }
                }
            },
            validate: function () {
                var inputs;
                var idx;
                var result = false;
                var length;
                var isValid = this.value();
                this._errors = {};
                if (!this.element.is(INPUTSELECTOR)) {
                    var invalid = false;
                    inputs = this.element.find(this._inputSelector);
                    for (idx = 0, length = inputs.length; idx < length; idx++) {
                        if (!this.validateInput(inputs.eq(idx))) {
                            invalid = true;
                        }
                    }
                    result = !invalid;
                } else {
                    result = this.validateInput(this.element);
                }
                this.trigger(VALIDATE, { valid: result });
                if (isValid !== result) {
                    this.trigger(CHANGE);
                }
                return result;
            },
            validateInput: function (input) {
                input = $(input);
                this._isValidated = true;
                var that = this, template = that._errorTemplate, result = that._checkValidity(input), valid = result.valid, className = '.' + INVALIDMSG, fieldName = input.attr(NAME) || '', lbl = that._findMessageContainer(fieldName).add(input.next(className).filter(function () {
                        var element = $(this);
                        if (element.filter('[' + kendo.attr('for') + ']').length) {
                            return element.attr(kendo.attr('for')) === fieldName;
                        }
                        return true;
                    })).hide(), messageText, wasValid = !input.attr('aria-invalid');
                input.removeAttr('aria-invalid');
                if (!valid) {
                    messageText = that._extractMessage(input, result.key);
                    that._errors[fieldName] = messageText;
                    var messageLabel = parseHtml(template({ message: decode(messageText) }));
                    var lblId = lbl.attr('id');
                    that._decorateMessageContainer(messageLabel, fieldName);
                    if (lblId) {
                        messageLabel.attr('id', lblId);
                    }
                    if (!lbl.replaceWith(messageLabel).length) {
                        messageLabel.insertAfter(input);
                    }
                    messageLabel.show();
                    input.attr('aria-invalid', true);
                } else {
                    delete that._errors[fieldName];
                }
                if (wasValid !== valid) {
                    this.trigger(VALIDATE_INPUT, {
                        valid: valid,
                        input: input
                    });
                }
                input.toggleClass(INVALIDINPUT, !valid);
                input.toggleClass(VALIDINPUT, valid);
                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', MOUSEDOWN = 'down', DOCUMENT_ELEMENT = $(document.documentElement), 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);
                that.downEvent = kendo.applyEventMap(MOUSEDOWN, kendo.guid());
                if (options.previousNext) {
                    if (!that.element.find(FIRST).length) {
                        that.element.append(icon(FIRST, options.messages.first, 'k-pager-first'));
                        first(that.element, page, totalPages);
                    }
                    if (!that.element.find(PREV).length) {
                        that.element.append(icon(PREV, options.messages.previous));
                        prev(that.element, page, totalPages);
                    }
                }
                if (options.numeric) {
                    that.list = that.element.find('.k-pager-numbers');
                    if (!that.list.length) {
                        that.list = $('<ul class="k-pager-numbers k-reset" />').appendTo(that.element);
                    }
                }
                if (options.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;
                DOCUMENT_ELEMENT.unbind(that.downEvent, $.proxy(that._hideList, that));
                if (e && e.action == 'itemchange') {
                    return;
                }
                if (options.numeric) {
                    if (page > buttonCount) {
                        reminder = page % buttonCount;
                        start = reminder === 0 ? page - buttonCount + 1 : page - reminder + 1;
                    }
                    end = Math.min(start + buttonCount - 1, totalPages);
                    if (start > 1) {
                        html += button(linkTemplate, start - 1, '...', false, options.messages.morePages);
                    }
                    for (idx = start; idx <= end; idx++) {
                        html += button(idx == page ? that.selectTemplate : linkTemplate, idx, idx, true);
                    }
                    if (end < totalPages) {
                        html += button(linkTemplate, idx, '...', false, options.messages.morePages);
                    }
                    if (html === '') {
                        html = that.selectTemplate({ text: 0 });
                    }
                    html = this.currentPageTemplate({ text: page }) + html;
                    that.list.removeClass('k-state-expanded').html(html);
                }
                if (options.info) {
                    if (total > 0) {
                        html = kendo.format(options.messages.display, 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 () {
                var that = this;
                if (that.list.hasClass('k-state-expanded')) {
                    DOCUMENT_ELEMENT.unbind(that.downEvent, $.proxy(that._hideList, that));
                } else {
                    DOCUMENT_ELEMENT.bind(that.downEvent, $.proxy(that._hideList, that));
                }
                that.list.toggleClass('k-state-expanded');
            },
            _hideList: function (e) {
                var that = this, target = kendo.eventTarget(e);
                if (!$.contains(that.list[0], target)) {
                    DOCUMENT_ELEMENT.unbind(that.downEvent, $.proxy(that._hideList, that));
                    that.list.removeClass('k-state-expanded');
                }
            },
            _click: function (e) {
                var target = $(e.currentTarget);
                e.preventDefault();
                if (!target.is('.k-state-disabled')) {
                    this.page(target.attr(kendo.attr('page')));
                }
            },
            totalPages: function () {
                return Math.ceil((this.dataSource.total() || 0) / (this.pageSize() || 1));
            },
            pageSize: function () {
                return this.dataSource.pageSize() || this.dataSource.total();
            },
            page: function (page) {
                if (page !== undefined) {
                    if (this.trigger('pageChange', { index: page })) {
                        return;
                    }
                    this.dataSource.page(page);
                    this.trigger(CHANGE, { index: page });
                } else {
                    if (this.dataSource.total() > 0) {
                        return this.dataSource.page();
                    } else {
                        return 0;
                    }
                }
            }
        });
        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, true);
                });
                return offsetHeight;
            },
            _height: function (length) {
                var that = this;
                var list = that.list;
                var height = that.options.height;
                var visible = that.popup.visible();
                var offsetTop;
                var popups;
                var footerHeight;
                if (length || that.options.noDataTemplate) {
                    popups = list.add(list.parent('.k-animation-container')).show();
                    if (!list.is(':visible')) {
                        popups.hide();
                        return;
                    }
                    height = that.listView.content[0].scrollHeight > height ? height : 'auto';
                    popups.height(height);
                    if (height !== 'auto') {
                        offsetTop = that._offsetHeight();
                        footerHeight = outerHeight($(that.footer)) || 0;
                        height = height - offsetTop - footerHeight;
                    }
                    that.listView.content.height(height);
                    if (!visible) {
                        popups.hide();
                    }
                }
                return height;
            },
            _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),
                    autosize: that.options.autoWidth
                }));
            },
            _makeUnselectable: function () {
                if (isIE8) {
                    this.list.find('*').not('.k-textbox').attr('unselectable', 'on');
                }
            },
            _toggleHover: function (e) {
                $(e.currentTarget).toggleClass(HOVER, e.type === 'mouseenter');
            },
            _toggle: function (open, preventFocus) {
                var that = this;
                var touchEnabled = support.mobileOS && (support.touch || support.MSPointers || support.pointers);
                open = open !== undefined ? open : !that.popup.visible();
                if (!preventFocus && !touchEnabled && that._focused[0] !== activeElement()) {
                    that._prevent = true;
                    that._focused.focus();
                    that._prevent = false;
                }
                that[open ? OPEN : CLOSE]();
            },
            _triggerCascade: function () {
                var that = this;
                if (!that._cascadeTriggered || that._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 (e) {
                var that = this;
                if (e.isDefaultPrevented()) {
                    return;
                }
                that._request = true;
                if (that._busy) {
                    return;
                }
                that._busy = setTimeout(function () {
                    if (that._arrowIcon) {
                        that._focused.attr('aria-busy', true);
                        that._arrowIcon.addClass(LOADING);
                        that._hideClear();
                    }
                }, 100);
            },
            _requestEnd: function () {
                this._request = false;
                this._hideBusy();
            },
            _dataSource: function () {
                var that = this, element = that.element, options = that.options, dataSource = options.dataSource || {}, idx;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (that._isSelect) {
                    idx = element[0].selectedIndex;
                    if (idx > -1) {
                        options.index = idx;
                    }
                    dataSource.select = element;
                    dataSource.fields = [
                        { field: options.dataTextField },
                        { field: options.dataValueField }
                    ];
                }
                if (that.dataSource) {
                    that._unbindDataSource();
                } else {
                    that._requestStartHandler = proxy(that._showBusy, that);
                    that._requestEndHandler = proxy(that._requestEnd, that);
                    that._errorHandler = proxy(that._hideBusy, that);
                }
                that.dataSource = kendo.data.DataSource.create(dataSource).bind(REQUESTSTART, that._requestStartHandler).bind(REQUESTEND, that._requestEndHandler).bind('error', that._errorHandler);
            },
            _firstItem: function () {
                this.listView.focusFirst();
            },
            _lastItem: function () {
                this.listView.focusLast();
            },
            _nextItem: function () {
                this.listView.focusNext();
            },
            _prevItem: function () {
                this.listView.focusPrev();
            },
            _move: function (e) {
                var that = this;
                var listView = that.listView;
                var key = e.keyCode;
                var down = key === keys.DOWN;
                var dataItem;
                var pressed;
                var current;
                if (key === keys.UP || down) {
                    if (e.altKey) {
                        that.toggle(down);
                    } else {
                        if (!listView.bound()) {
                            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('paste' + ns, proxy(that._paste, that)).on('keydown' + ns, proxy(that._keydown, that)).on(INPUT_EVENT_NAME, proxy(that._input, that)).on('mouseup' + ns, proxy(that._mouseUp, that)).on('DOMMouseScroll' + ns + ' mousewheel' + ns, proxy(that._scroll, that));
            },
            _unbindInput: function () {
                this.element.off('keydown' + ns).off('paste' + ns).off(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);
                }
            },
            _paste: function (e) {
                e.preventDefault();
            },
            _keydown: function (e) {
                var key = e.keyCode;
                var selection;
                if (key == 37 || key == 39) {
                    e.preventDefault();
                    selection = caret(this.element[0]);
                    if (selection[0] != selection[1]) {
                        this._selectNearestSegment();
                    }
                    var dir = key == 37 ? -1 : 1;
                    var index = dir == -1 ? caret(this.element[0])[0] - 1 : caret(this.element[0])[1] + 1;
                    while (index >= 0 && index < this._format.length) {
                        if (knownSymbols.indexOf(this._format[index]) >= 0) {
                            this._selectSegment(this._format[index]);
                            break;
                        }
                        index += dir;
                    }
                }
                if (key == 38 || key == 40) {
                    e.preventDefault();
                    selection = caret(this.element[0]);
                    var symbol = this._format[selection[0]];
                    if (knownSymbols.indexOf(symbol) >= 0) {
                        this._dateTime.modifyPart(symbol, key == 38 ? 1 : -1);
                        this._updateElementValue();
                        this._selectSegment(symbol);
                    }
                }
                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 || dataItem === 0) {
                    text = dataItem;
                    value = that._dataValue(dataItem);
                    if (optionLabel) {
                        idx += 1;
                    }
                } else if (optionLabel) {
                    that._focus(that.optionLabel.addClass('k-state-selected'));
                    text = that._optionLabelText();
                    if (typeof optionLabel === 'string') {
                        value = '';
                    } else {
                        value = that._value(optionLabel);
                    }
                    idx = 0;
                }
                that.selectedIndex = idx;
                if (value === null) {
                    value = '';
                }
                that._textAccessor(text);
                that._accessor(value, idx);
                that._triggerCascade();
            },
            _mobile: function () {
                var that = this, popup = that.popup, mobileOS = support.mobileOS, root = popup.element.parents('.km-root').eq(0);
                if (root.length && mobileOS) {
                    popup.options.animation.open.effects = mobileOS.android || mobileOS.meego ? 'fadeIn' : mobileOS.ios || mobileOS.wp ? 'slideIn:up' : popup.options.animation.open.effects;
                }
            },
            _filterHeader: function () {
                var icon;
                if (this.filterInput) {
                    this.filterInput.off(ns).parent().remove();
                    this.filterInput = null;
                }
                if (this._isFilterEnabled()) {
                    icon = '<span class="k-icon k-i-zoom"></span>';
                    this.filterInput = $('<input class="k-textbox"/>').attr({
                        placeholder: this.element.attr('placeholder'),
                        title: this.element.attr('title'),
                        role: 'listbox',
                        'aria-haspopup': true,
                        'aria-expanded': false
                    });
                    this.list.prepend($('<span class="k-list-filter" />').append(this.filterInput.add(icon)));
                }
            },
            _span: function () {
                var that = this, wrapper = that.wrapper, SELECTOR = 'span.k-input', span;
                span = wrapper.find(SELECTOR);
                if (!span[0]) {
                    wrapper.append('<span unselectable="on" class="k-dropdown-wrap k-state-default"><span unselectable="on" class="k-input">&nbsp;</span><span unselectable="on" class="k-select" aria-label="select"><span class="k-icon k-i-arrow-60-down"></span></span></span>').append(that.element);
                    span = wrapper.find(SELECTOR);
                }
                that.span = span;
                that._inputWrapper = $(wrapper[0].firstChild);
                that._arrow = wrapper.find('.k-select');
                that._arrowIcon = that._arrow.find('.k-icon');
            },
            _wrapper: function () {
                var that = this, element = that.element, DOMelement = element[0], wrapper;
                wrapper = element.parent();
                if (!wrapper.is('span.k-widget')) {
                    wrapper = element.wrap('<span />').parent();
                    wrapper[0].style.cssText = DOMelement.style.cssText;
                    wrapper[0].title = DOMelement.title;
                }
                that._focused = that.wrapper = wrapper.addClass('k-widget k-dropdown 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 length = data.length;
                var groupsLength = that.dataSource._group.length;
                var isFirstPage = skip === undefined || skip === 0;
                that._presetValue = false;
                that._renderFooter();
                that._renderNoData();
                that._toggleNoData(!length);
                that._toggleHeader(!!groupsLength && !!length);
                that._resizePopup();
                that.popup.position();
                that._buildOptions(data);
                that._makeUnselectable();
                that._updateSelection();
                if (data.length && isFirstPage) {
                    that._updateItemFocus();
                    if (that.options.suggest && isActive && that.input.val()) {
                        that.suggest(data[0]);
                    }
                }
                if (that._open) {
                    that._open = false;
                    if (that._typingTimeout && !isActive) {
                        that.popup.close();
                    } else {
                        that.toggle(that._allowOpening());
                    }
                    that._typingTimeout = null;
                }
                that._hideBusy();
                that.trigger('dataBound');
            },
            _listChange: function () {
                this._selectValue(this.listView.selectedDataItems()[0]);
                if (this._presetValue) {
                    this._oldIndex = this.selectedIndex;
                }
            },
            _get: function (candidate) {
                var data, found, idx;
                if (typeof candidate === 'function') {
                    data = this.dataSource.flatView();
                    for (idx = 0; idx < data.length; idx++) {
                        if (candidate(data[idx])) {
                            candidate = idx;
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        candidate = -1;
                    }
                }
                return candidate;
            },
            _select: function (candidate, keepState) {
                var that = this;
                candidate = that._get(candidate);
                if (candidate === -1) {
                    that.input[0].value = '';
                    that._accessor('');
                }
                return that.listView.select(candidate).done(function () {
                    if (!keepState && that._state === STATE_FILTER) {
                        that._state = STATE_ACCEPT;
                    }
                });
            },
            _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 || dataItem === 0) {
                        value = this._dataValue(dataItem);
                        text = this._text(dataItem);
                    }
                    if (value === null) {
                        value = '';
                    }
                }
                this._setDomInputValue(text);
                this._accessor(value !== undefined ? value : text, idx);
                this._placeholder();
                this._triggerCascade();
            },
            _setDomInputValue: function (text) {
                var that = this;
                var currentCaret = caret(this.input);
                var caretStart;
                if (currentCaret && currentCaret.length) {
                    caretStart = currentCaret[0];
                }
                this._prev = this.input[0].value = text;
                if (caretStart && this.selectedIndex === -1) {
                    var mobile = support.mobileOS;
                    if (mobile.wp || mobile.android) {
                        setTimeout(function () {
                            that.input[0].setSelectionRange(caretStart, caretStart);
                        }, 0);
                    } else {
                        this.input[0].setSelectionRange(caretStart, caretStart);
                    }
                }
            },
            refresh: function () {
                this.listView.refresh();
            },
            _toggleCloseVisibility: function () {
                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);
                    if (result === NULL) {
                        that._update(value);
                    } else {
                        element.value = result.toString().replace(POINT, numberFormat[POINT]);
                        if (that._adjust(result) !== result || !that._numericRegex(numberFormat).test(element.value)) {
                            that._update(value);
                        }
                    }
                });
            },
            _option: function (option, value) {
                var that = this, element = that.element, options = that.options;
                if (value === undefined) {
                    return options[option];
                }
                value = that._parse(value);
                if (!value && option === 'step') {
                    return;
                }
                options[option] = value;
                element.add(that._text).attr('aria-value' + option, value);
                element.attr(option, value);
            },
            _spin: function (step, timeout) {
                var that = this;
                timeout = timeout || 500;
                clearTimeout(that._spinning);
                that._spinning = setTimeout(function () {
                    that._spin(step, 50);
                }, timeout);
                that._step(step);
            },
            _step: function (step) {
                var that = this, element = that.element, 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);
                }
                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) {
                e.sender.element.children('.' + FOCUSEDSTATE).removeClass(FOCUSEDSTATE);
                if (this.options.scrollable) {
                    this._setPopupHeight(e.sender);
                }
            },
            _setPopupHeight: function (popup, isFixed) {
                var popupElement = popup.element;
                var popups = popupElement.add(popupElement.parent(animationContainerSelector));
                popups.height(popupElement.hasClass(MENU) && this._initialHeight || '');
                var location = popup._location(isFixed);
                var windowHeight = $(window).height();
                var popupOuterHeight = location.height;
                var popupOffsetTop = isFixed ? 0 : Math.max(location.top, 0);
                var scrollTop = isFixed ? 0 : parentsScroll(this._overflowWrapper()[0], 'scrollTop');
                var bottomScrollbar = window.innerHeight - windowHeight;
                var maxHeight = windowHeight - kendo.getShadows(popupElement).bottom + bottomScrollbar;
                var canFit = maxHeight + scrollTop > popupOuterHeight + popupOffsetTop;
                if (!canFit) {
                    var height = Math.min(maxHeight, maxHeight - popupOffsetTop + scrollTop);
                    popups.css({
                        overflow: 'hidden',
                        height: height + 'px'
                    });
                }
            },
            close: function (items, dontClearClose) {
                var that = this;
                var overflowWrapper = that._overflowWrapper();
                var element = overflowWrapper || that.element;
                items = element.find(items);
                if (!items.length) {
                    items = element.find('>.k-item');
                }
                var hasChildPopupsHovered = function (currentPopup) {
                    var result = false;
                    if ($.isEmptyObject(that._openedPopups)) {
                        return result;
                    }
                    $(getChildPopups(currentPopup, overflowWrapper)).each(function (i, popup) {
                        result = !!that._openedPopups[popup.data(POPUP_ID_ATTR).toString()];
                        return !result;
                    });
                    return result;
                };
                var isPopupMouseLeaved = function (opener) {
                    var groupId = opener.data(POPUP_OPENER_ATTR);
                    return !overflowWrapper || !groupId || !that._openedPopups[groupId.toString()];
                };
                items.each(function () {
                    var li = $(this);
                    if (!dontClearClose && that._isRootItem(li)) {
                        that.clicked = false;
                    }
                    clearTimeout(li.data(TIMER));
                    li.data(TIMER, setTimeout(function () {
                        var popup = that._getPopup(li);
                        if (popup && (isPopupMouseLeaved(li) || that._forceClose)) {
                            if (!that._forceClose && hasChildPopupsHovered(popup.element)) {
                                return;
                            }
                            popup.close();
                            popup.element.attr('aria-hidden', true);
                            if (overflowWrapper) {
                                if (that._forceClose && items.last().is(li[0])) {
                                    delete that._forceClose;
                                }
                            }
                        }
                    }, that.options.hoverDelay));
                });
                return that;
            },
            _getPopup: function (li) {
                var that = this;
                var popup = li.find('.k-menu-group:not(.k-list-container):not(.k-calendar-container):first:visible').data(KENDOPOPUP);
                var overflowWrapper = that._overflowWrapper();
                if (!popup && overflowWrapper) {
                    var groupId = li.data(POPUP_OPENER_ATTR);
                    if (groupId) {
                        var popupElement = overflowWrapper.find(popupGroupSelector(groupId));
                        popup = popupElement.data(KENDOPOPUP);
                    }
                }
                return popup;
            },
            _toggleDisabled: function (items, enable) {
                this.element.find(items).each(function () {
                    $(this).toggleClass(DEFAULTSTATE, enable).toggleClass(DISABLEDSTATE, !enable).attr('aria-disabled', !enable);
                });
            },
            _toggleHover: function (e) {
                var target = $(kendo.eventTarget(e) || e.target).closest(allItemsSelector), isEnter = e.type == MOUSEENTER || MOUSEDOWN.indexOf(e.type) !== -1;
                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));
                if (element.is('th')) {
                    var table = element.closest('table');
                    if (table.parent().hasClass('k-grid-header-wrap')) {
                        table = table.closest('.k-grid').find('.k-grid-content > table');
                    } else if (!table.parent().hasClass('k-grid')) {
                        table = null;
                    }
                    if (table) {
                        element.toggleClass('k-sorted', dir !== undefined);
                        table.children('colgroup').children().eq(element.index()).toggleClass('k-sorted', dir !== undefined);
                    }
                }
                element.find('.k-i-sort-asc-sm,.k-i-sort-desc-sm,.k-sort-order').remove();
                if (dir === ASC) {
                    $('<span class="k-icon k-i-sort-asc-sm" />').appendTo(that.link);
                    element.attr(ARIASORT, 'ascending');
                } else if (dir === DESC) {
                    $('<span class="k-icon k-i-sort-desc-sm" />').appendTo(that.link);
                    element.attr(ARIASORT, 'descending');
                }
                if (that.options.showIndexes && sort.length > 1 && sortOrder) {
                    $('<span class="k-sort-order" />').html(sortOrder).appendTo(that.link);
                }
            },
            _toggleSortDirection: function (dir) {
                var directions = this.directions;
                if (dir === directions[directions.length - 1] && this.options.allowUnsort) {
                    return undefined;
                }
                return directions[0] === dir ? directions[1] : directions[0];
            },
            _click: function (e) {
                var that = this, element = that.element, field = element.attr(kendo.attr(FIELD)), dir = element.attr(kendo.attr(DIR)), options = that.options, compare = that.options.compare === null ? undefined : that.options.compare, sort = that.dataSource.sort() || [], idx, length;
                e.preventDefault();
                if (options.filter && !element.is(options.filter)) {
                    return;
                }
                dir = this._toggleSortDirection(dir);
                if (this.trigger('change', {
                        sort: {
                            field: field,
                            dir: dir,
                            compare: compare
                        }
                    })) {
                    return;
                }
                if (options.mode === SINGLE) {
                    sort = [{
                            field: field,
                            dir: dir,
                            compare: compare
                        }];
                } else if (options.mode === 'multiple') {
                    for (idx = 0, length = sort.length; idx < length; idx++) {
                        if (sort[idx].field === field) {
                            sort.splice(idx, 1);
                            break;
                        }
                    }
                    sort.push({
                        field: field,
                        dir: dir,
                        compare: compare
                    });
                }
                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', zero = /^0[a-z]*$/i, 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 (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();
                if (options.pinned) {
                    that.pin();
                }
                id = element.attr('id');
                if (id) {
                    id = id + '_wnd_title';
                    wrapper.children(KWINDOWTITLEBAR).children(KWINDOWTITLE).attr('id', id);
                    windowContent.attr({
                        'role': 'dialog',
                        'aria-labelledby': id
                    });
                }
                wrapper.add(wrapper.children('.k-resize-handle,' + KWINDOWTITLEBAR)).on('mousedown' + NS, proxy(that.toFront, that));
                that.touchScroller = kendo.touchScroller(element);
                that._resizeHandler = proxy(that._onDocumentResize, that);
                that._marker = kendo.guid().substring(0, 8);
                $(window).on('resize' + NS + that._marker, that._resizeHandler);
                if (options.visible) {
                    that.trigger(OPEN);
                    that.trigger(ACTIVATE);
                }
                kendo.notify(that);
                if (this.options.modal) {
                    this._tabKeyTrap = new TabKeyTrap(wrapper);
                    this._tabKeyTrap.trap();
                    this._tabKeyTrap.shouldTrap = function () {
                        return windowContent.data('isFront');
                    };
                }
            },
            _buttonEnter: function (e) {
                $(e.currentTarget).addClass(KHOVERSTATE);
            },
            _buttonLeave: function (e) {
                $(e.currentTarget).removeClass(KHOVERSTATE);
            },
            _focus: function () {
                this.wrapper.addClass(KFOCUSEDSTATE);
            },
            _blur: function () {
                this.wrapper.removeClass(KFOCUSEDSTATE);
            },
            _dimensions: function () {
                var wrapper = this.wrapper;
                var options = this.options;
                var width = options.width;
                var height = options.height;
                var maxHeight = options.maxHeight;
                var 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 options = this.options;
                var actions = options.actions;
                var pinned = options.pinned;
                var titlebar = this.wrapper.children(KWINDOWTITLEBAR);
                var container = titlebar.find('.k-window-actions');
                var windowSpecificCommands = [
                    'maximize',
                    'minimize'
                ];
                actions = $.map(actions, function (action) {
                    action = pinned && action.toLowerCase() === 'pin' ? 'unpin' : action;
                    return { name: windowSpecificCommands.indexOf(action.toLowerCase()) > -1 ? 'window-' + action : action };
                });
                container.html(kendo.render(templates.action, actions));
            },
            setOptions: function (options) {
                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 () {
                var that = this, win = $(window), wrapper = that.wrapper, top = parseInt(wrapper.css('top'), 10), left = parseInt(wrapper.css('left'), 10);
                if (!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;
                    that.options.draggable = false;
                }
            },
            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.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;
                    that.options.draggable = true;
                }
            },
            _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));
        }
        function getPosition(elem) {
            var result = {
                    top: elem.offsetTop,
                    left: elem.offsetLeft
                }, parent = elem.offsetParent;
            while (parent) {
                result.top += parent.offsetTop;
                result.left += parent.offsetLeft;
                var parentOverflowX = $(parent).css('overflowX');
                var parentOverflowY = $(parent).css('overflowY');
                if (parentOverflowY === 'auto' || parentOverflowY === 'scroll') {
                    result.top -= parent.scrollTop;
                }
                if (parentOverflowX === 'auto' || parentOverflowX === 'scroll') {
                    result.left -= parent.scrollLeft;
                }
                parent = parent.offsetParent;
            }
            return result;
        }
        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');
                var offsetParent = wrapper.offsetParent();
                if (offsetParent.is('html')) {
                    that.containerOffset.top = that.containerOffset.left = 0;
                } else {
                    var marginTop = offsetParent.css('margin-top');
                    var marginLeft = offsetParent.css('margin-left');
                    var hasMargin = !zero.test(marginTop) || !zero.test(marginLeft);
                    if (hasMargin) {
                        var wrapperPosition = getPosition(wrapper[0]);
                        var relativeElMarginLeft = wrapperPosition.left - that.containerOffset.left - that.initialPosition.left;
                        var relativeElMarginTop = wrapperPosition.top - that.containerOffset.top - that.initialPosition.top;
                        that._relativeElMarginLeft = relativeElMarginLeft > 1 ? relativeElMarginLeft : 0;
                        that._relativeElMarginTop = relativeElMarginTop > 1 ? relativeElMarginTop : 0;
                        that.initialPosition.left += that._relativeElMarginLeft;
                        that.initialPosition.top += that._relativeElMarginTop;
                    }
                }
                wrapper.children(KWINDOWRESIZEHANDLES).not(e.currentTarget).hide();
                $(BODY).css(CURSOR, e.currentTarget.css(CURSOR));
            },
            drag: function (e) {
                if (this._preventDragging) {
                    return;
                }
                var that = this, wnd = that.owner, wrapper = wnd.wrapper, options = wnd.options, 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 - (that._relativeElMarginLeft || 0),
                        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 - (that._relativeElMarginTop || 0),
                        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) || !wnd.options.draggable;
                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', ITEMROW = 'tr:not(.k-grouping-row):not(.k-detail-row):not(.k-footer-template):not(.k-group-footer):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', CHECKBOX = 'k-checkbox', CHECKBOXINPUT = 'input[data-role=\'checkbox\'].' + CHECKBOX, 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 = '# if (iconClass) {#' + '<a role="button" class="k-button k-button-icontext #=className#" #=attr# href="\\#"><span class="#=iconClass# #=imageClass#"></span>#=text#</a>' + '# } else { #' + '<a role="button" class="k-button k-button-icontext #=className#" #=attr# href="\\#">#=text#</a>' + '# } #', SELECTCOLUMNTMPL = '<input class="' + CHECKBOX + '" data-role="checkbox" aria-label="Select row" aria-checked="false" type="checkbox"><label class="k-checkbox-label k-no-text">&\\#8203;</label>', SELECTCOLUMNHEADERTMPL = '<input class="' + CHECKBOX + '" data-role="checkbox" aria-label="Select all rows" aria-checked="false" type="checkbox"><label class="k-checkbox-label k-no-text">&#8203;</label>', isRtl = false, browser = kendo.support.browser, isIE7 = browser.msie && browser.version == 7, isIE8 = browser.msie && browser.version == 8;
        var 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 && !column.selectable) {
                                that.editCell(cell);
                                return false;
                            }
                        });
                    }
                    container = that.editView ? that.editView.element : that._editContainer;
                    if (container) {
                        if (!this._editCancelClickHandler) {
                            this._editCancelClickHandler = proxy(this._editCancelClick, this);
                        }
                        container.on(CLICK + NS, 'a.k-grid-cancel', this._editCancelClickHandler);
                        if (!this._editUpdateClickHandler) {
                            this._editUpdateClickHandler = proxy(this._editUpdateClick, this);
                        }
                        container.on(CLICK + NS, 'a.k-grid-update', this._editUpdateClickHandler);
                    }
                }
            },
            _editUpdateClick: function (e) {
                e.preventDefault();
                e.stopPropagation();
                this.saveRow();
            },
            _editCancelClick: function (e) {
                var that = this;
                var navigatable = that.options.navigatable;
                var model = that.editable.options.model;
                var container = that.editView ? that.editView.element : that._editContainer;
                e.preventDefault();
                e.stopPropagation();
                if (that.trigger('cancel', {
                        container: container,
                        model: model
                    })) {
                    return;
                }
                var currentIndex = that.items().index($(that.current()).parent());
                that.cancelRow();
                if (navigatable) {
                    that._setCurrent(that.items().eq(currentIndex).children().filter(NAVCELL).first());
                    focusTable(that.table, true);
                }
            },
            _createPopupEditor: function (model) {
                var that = this;
                var html = '<div ' + kendo.attr('uid') + '="' + model.uid + '" class="k-popup-edit-form' + (that._isMobile ? ' k-mobile-list' : '') + '"><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.selectable) {
                            continue;
                        }
                        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 || !!$.grep(leafColumns(that.columns), function (col) {
                            return col.selectable;
                        }).length)) {
                        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) {
                                that._persistSelectedRows();
                            }
                            that.trigger(CHANGE);
                        },
                        useAllItems: isLocked && multi && cell,
                        relatedTarget: function (items) {
                            if (cell || !isLocked) {
                                return;
                            }
                            var related;
                            var result = $();
                            for (var idx = 0, length = items.length; idx < length; idx++) {
                                related = that._relatedRow(items[idx]);
                                if (inArray(related[0], items) < 0) {
                                    result = result.add(related);
                                }
                            }
                            return result;
                        },
                        continuousItems: function () {
                            return that._continuousItems(filter, cell);
                        }
                    });
                    if (that.options.navigatable) {
                        elements.on('keydown' + NS, function (e) {
                            var current = that.current();
                            var target = e.target;
                            if (e.keyCode === keys.SPACEBAR && !e.shiftKey && $.inArray(target, elements) > -1 && !current.is('.k-edit-cell,.k-header') && current.parent().is(':not(.k-grouping-row,.k-detail-row,.k-group-footer)')) {
                                e.preventDefault();
                                e.stopPropagation();
                                current = cell ? current : current.parent();
                                if (isLocked && !cell) {
                                    current = current.add(that._relatedRow(current));
                                }
                                if (multi) {
                                    if (!e.ctrlKey) {
                                        that.selectable.clear();
                                    } else {
                                        if (current.hasClass(SELECTED)) {
                                            current.removeClass(SELECTED);
                                            that.trigger(CHANGE);
                                            return;
                                        }
                                    }
                                } else {
                                    that.selectable.clear();
                                }
                                if (!cell) {
                                    that.selectable._lastActive = current;
                                }
                                that.selectable.value(current);
                            } else if (!cell && (e.shiftKey && e.keyCode == keys.LEFT || e.shiftKey && e.keyCode == keys.RIGHT || e.shiftKey && e.keyCode == keys.UP || e.shiftKey && e.keyCode == keys.DOWN || e.keyCode === keys.SPACEBAR && e.shiftKey)) {
                                e.preventDefault();
                                e.stopPropagation();
                                current = current.parent();
                                if (isLocked) {
                                    current = current.add(that._relatedRow(current));
                                }
                                if (multi) {
                                    if (!that.selectable._lastActive) {
                                        that.selectable._lastActive = current;
                                    }
                                    that.selectable.selectRange(that.selectable._firstSelectee(), current);
                                } else {
                                    that.selectable.clear();
                                    that.selectable.value(current);
                                }
                            }
                        });
                    }
                }
            },
            _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;
                if (that.selectable) {
                    that.selectable.clear();
                }
                if ($.grep(leafColumns(that.columns), function (col) {
                        return col.selectable;
                    }).length) {
                    that._deselectCheckRows(that.select());
                }
                if (that.options.persistSelection) {
                    that._persistSelectedRows();
                }
                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 && !selectable.options.multiple) {
                        selectable.clear();
                        items = items.first();
                    }
                    if (that._isLocked()) {
                        items = items.add(items.map(function () {
                            return that._relatedRow(this);
                        }));
                    }
                    if (selectable) {
                        selectable.value(items);
                    } else {
                        items.each(function () {
                            $(this).addClass(SELECTED).find(CHECKBOXINPUT).prop('checked', true).attr('aria-label', 'Deselect row').attr('aria-checked', true);
                        });
                        if (that.select().length === that.items().length) {
                            that._toggleHeaderCheckState(true);
                        }
                        if (that.options.persistSelection) {
                            that._persistSelectedRows();
                        }
                        that.trigger(CHANGE);
                    }
                    return;
                }
                return selectable ? selectable.value() : that.items().filter('.' + SELECTED);
            },
            _toggleHeaderCheckState: function (checked) {
                var that = this;
                if (checked) {
                    that.thead.add(that.lockedHeader).find('tr ' + CHECKBOXINPUT).prop('checked', true).attr('aria-checked', true).attr('aria-label', 'Deselect all rows');
                } else {
                    that.thead.add(that.lockedHeader).find('tr ' + CHECKBOXINPUT).prop('checked', false).attr('aria-checked', false).attr('aria-label', 'Select all rows');
                }
            },
            _deselectCheckRows: function (items) {
                var that = this;
                items = that.table.add(that.lockedTable).find(items);
                items.each(function () {
                    $(this).removeClass(SELECTED).find(CHECKBOXINPUT).attr('aria-checked', false).prop('checked', false).attr('aria-label', 'Select row');
                });
                that._toggleHeaderCheckState(false);
                if (that.options.persistSelection) {
                    that._persistSelectedRows();
                }
                that.trigger(CHANGE);
            },
            _persistSelectedRows: function () {
                var that = this, key, dataItem, allRows = that.items(), dataSourceOptions = that.dataSource.options, modelId = dataSourceOptions.schema.model.id, selectedViewIds = {};
                that.select().each(function () {
                    dataItem = that.dataItem(this);
                    selectedViewIds[dataItem[modelId]] = true;
                });
                for (var i = 0; i < allRows.length; i++) {
                    dataItem = that.dataItem(allRows[i]);
                    key = dataItem[modelId];
                    if (selectedViewIds[key]) {
                        that._selectedIds[key] = true;
                    } else {
                        delete that._selectedIds[key];
                    }
                }
            },
            selectedKeyNames: function () {
                var that = this, ids = [];
                for (var property in that._selectedIds) {
                    ids.push(property);
                }
                ids.sort();
                return ids;
            },
            _updateCurrentAttr: function (current, next) {
                var headerId = $(current).data('headerId');
                $(current).removeClass(FOCUSED).closest('table').removeAttr('aria-activedescendant');
                if (headerId) {
                    headerId = headerId.replace(this._cellId, '');
                    $(current).attr('id', headerId);
                } else {
                    $(current).removeAttr('id');
                }
                next.data('headerId', next.attr('id')).attr('id', this._cellId).addClass(FOCUSED).closest('table').attr('aria-activedescendant', this._cellId);
                this._current = next;
            },
            _scrollCurrent: function () {
                var current = this._current;
                var scrollable = this.options.scrollable;
                if (!current || !scrollable) {
                    return;
                }
                var row = current.parent();
                var tableContainer = row.closest('table').parent();
                var isInLockedContainer = tableContainer.is('.k-grid-content-locked,.k-grid-header-locked');
                var isInContent = tableContainer.is('.k-grid-content-locked,.k-grid-content,.k-virtual-scrollable-wrap');
                var scrollableContainer = $(this.content).find('>.k-virtual-scrollable-wrap').addBack().last()[0];
                if (isInContent) {
                    if (scrollable.virtual) {
                        var rowIndex = Math.max(inArray(row[0], this._items(row.parent())), 0);
                        this._rowVirtualIndex = this.virtualScrollable.itemIndex(rowIndex);
                        this.virtualScrollable.scrollIntoView(row);
                    } else {
                        this._scrollTo(this._relatedRow(row)[0], scrollableContainer);
                    }
                }
                if (this.lockedContent) {
                    this.lockedContent[0].scrollTop = scrollableContainer.scrollTop;
                }
                if (!isInLockedContainer) {
                    this._scrollTo(current[0], scrollableContainer);
                }
            },
            current: function (next) {
                return this._setCurrent(next, true);
            },
            _setCurrent: function (next, preventTrigger) {
                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, e.shiftKey);
                }
                if (canHandle && e.keyCode == keys.DOWN) {
                    handled = this._moveDown(current, e.shiftKey);
                }
                if (canHandle && e.keyCode == (isRtl ? keys.LEFT : keys.RIGHT)) {
                    handled = this._moveRight(current, e.altKey, e.shiftKey, e.currentTarget);
                }
                if (canHandle && e.keyCode == (isRtl ? keys.RIGHT : keys.LEFT)) {
                    handled = this._moveLeft(current, e.altKey, e.shiftKey, e.currentTarget);
                }
                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, shiftKey, currentTable) {
                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]) {
                        if (shiftKey) {
                            if (this.lockedTable) {
                                next = this._relatedRow(row);
                                if ($.contains(this.lockedTable[0], row[0])) {
                                    next = next.prevAll(ITEMROW + ':first');
                                }
                                next = next.children(DATA_CELL + ':last');
                            } else {
                                next = this._tabNext(current, currentTable, true);
                            }
                        } else {
                            container = this._horizontalContainer(container);
                            next = this._prevHorizontalCell(container, current, index);
                            if (next[0] !== current[0]) {
                                focusTable(container.parent(), true);
                            }
                        }
                    }
                    this._setCurrent(next);
                }
                return true;
            },
            _moveRight: function (current, altKey, shiftKey, currentTable) {
                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]) {
                        if (shiftKey) {
                            if (this.lockedTable) {
                                next = this._relatedRow(row);
                                if ($.contains(this.table[0], row[0])) {
                                    next = next.nextAll(ITEMROW + ':first');
                                }
                                next = next.children(DATA_CELL + ':first');
                            } else {
                                next = this._tabNext(current, currentTable, false);
                            }
                        } else {
                            container = this._horizontalContainer(container, true);
                            next = this._nextHorizontalCell(container, current, index);
                            if (next[0] !== current[0]) {
                                focusTable(container.parent(), true);
                            }
                        }
                    }
                    this._setCurrent(next);
                }
                return true;
            },
            _moveUp: function (current, shiftKey) {
                var container = current.parent().parent();
                var next;
                if (shiftKey) {
                    next = current.parent();
                    next = next.prevAll(ITEMROW + ':first');
                    next = current.parent().is(ITEMROW) ? next.children().eq(current.index()) : next.children(DATA_CELL + ':last');
                } else {
                    next = this._prevVerticalCell(container, current);
                    if (!next[0]) {
                        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, shiftKey) {
                var container = current.parent().parent();
                var next;
                if (shiftKey) {
                    next = current.parent();
                    next = next.nextAll(ITEMROW + ':first');
                    next = current.parent().is(ITEMROW) ? next.children().eq(current.index()) : next.children(DATA_CELL + ':first');
                } else {
                    next = this._nextVerticalCell(container, current);
                    if (!next[0]) {
                        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);
                if ($.grep(leafColumns(that.columns), function (col) {
                        return col.selectable;
                    }).length) {
                    if (that.options.persistSelection) {
                        that._selectedIds = {};
                    }
                    that.wrapper.on(CLICK + NS, 'tbody > tr ' + CHECKBOXINPUT, proxy(that._checkboxClick, that));
                    that.wrapper.on(CLICK + NS, 'thead > tr ' + CHECKBOXINPUT, proxy(that._headerCheckboxClick, that));
                }
            },
            _headerCheckboxClick: function (e) {
                var that = this, checkBox = $(e.target), checked = checkBox.prop('checked'), parentGrid = checkBox.closest('.k-grid.k-widget').getKendoGrid();
                if (that !== parentGrid) {
                    return;
                }
                if (checked) {
                    that.select(parentGrid.items());
                } else {
                    that.clearSelection();
                }
            },
            _checkboxClick: function (e) {
                var that = this, row = $(e.target).closest('tr'), isSelecting = !row.hasClass(SELECTED);
                if (that !== row.closest('.k-grid.k-widget').getKendoGrid()) {
                    return;
                }
                if (isSelecting) {
                    that.select(row);
                } else {
                    that._deselectCheckRows(row);
                }
            },
            _groups: function () {
                var group = this.dataSource.group();
                return group ? group.length : 0;
            },
            _tmpl: function (rowTemplate, columns, alt, skipGroupCells) {
                var that = this, settings = extend({}, kendo.Template, that.options.templateSettings), 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 (column.selectable) {
                    return SELECTCOLUMNTMPL;
                }
                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.selectable) {
                        html += '<th scope=\'col\'' + stringifyAttributes(th.headerAttributes);
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (index > -1) {
                            html += kendo.attr('index') + '=\'' + index + '\'';
                        }
                        text = th.headerTemplate ? text : SELECTCOLUMNHEADERTMPL;
                        html += '>' + text + '</th>';
                    } else if (th.command) {
                        html += '<th scope=\'col\'' + stringifyAttributes(th.headerAttributes);
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (index > -1) {
                            html += kendo.attr('index') + '=\'' + index + '\'';
                        }
                        html += '>' + text + '</th>';
                    } else {
                        if (th.field) {
                            field = kendo.attr('field') + '=\'' + th.field + '\' ';
                        }
                        html += '<th scope=\'col\' role=\'columnheader\' ' + field;
                        html += ' aria-haspopup=\'true\'';
                        if (rowSpan && !columns[idx].colSpan) {
                            html += ' rowspan=\'' + rowSpan + '\'';
                        }
                        if (columns[idx].colSpan > 1) {
                            html += 'colspan="' + (columns[idx].colSpan - hiddenLeafColumnsCount(th.columns)) + '" ';
                            html += kendo.attr('colspan') + '=\'' + columns[idx].colSpan + '\'';
                        }
                        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>';
                    }
                }
                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, hasCheckBoxColumn = !!$.grep(leafColumns(that.columns), function (col) {
                        return col.selectable;
                    }).length, 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 (hasCheckBoxColumn) {
                    that._toggleHeaderCheckState(false);
                }
                if (that.options.persistSelection && (that.selectable && !kendo.ui.Selectable.parseOptions(that.options.selectable).cell || hasCheckBoxColumn)) {
                    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, allRows = that.items(), selectedRows;
                selectedRows = grep(allRows, function (row) {
                    var dataItemKey = that.dataItem(row)[that.dataSource.options.schema.model.id];
                    if (that._selectedIds[dataItemKey]) {
                        return row;
                    }
                });
                that.select(selectedRows);
            },
            _angularItems: function (cmd) {
                kendo.ui.DataBoundWidget.fn._angularItems.call(this, cmd);
                if (cmd === 'cleanup') {
                    this._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 || column.selectable) {
                return false;
            }
            if (model.editable && !model.editable(column.field)) {
                return false;
            }
            if (column.editable && !column.editable(model)) {
                return false;
            }
            return true;
        }
        function isInputElement(element) {
            return $(element).is(':button,a,:input,a>.k-icon,textarea,span.k-select,span.k-icon,span.k-link,.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'
                };
                var firstActionButton;
                if (!classDictionary.hasOwnProperty(actionKey)) {
                    return;
                }
                if (!skipClear) {
                    this._clearFileAction(fileElement);
                }
                if (!this.options.template) {
                    if (!skipClear) {
                        fileElement.find('.k-upload-status .k-upload-action').remove();
                    }
                    fileElement.find('.k-upload-status').append(this._renderAction(classDictionary[actionKey], this.localization[actionKey], iconsClassDictionary[actionKey]));
                } else {
                    firstActionButton = fileElement.find('.k-upload-action').first();
                    if (!firstActionButton.find('.k-icon').length) {
                        firstActionButton.addClass('k-button').append('<span class=\'k-icon ' + iconsClassDictionary[actionKey] + ' ' + classDictionary[actionKey] + '\' title=\'' + this.localization[actionKey] + '\'' + 'aria-label=\'' + this.localization[actionKey] + '\'></span>').show();
                    } else if (firstActionButton.next('.k-upload-action').length) {
                        firstActionButton.next('.k-upload-action').addClass('k-button').append('<span class=\'k-icon ' + iconsClassDictionary[actionKey] + ' ' + classDictionary[actionKey] + '\' title=\'' + this.localization[actionKey] + '\'' + 'aria-label=\'' + this.localization[actionKey] + '\'></span>').show();
                    }
                }
            },
            _fileState: function (fileEntry, stateKey) {
                var localization = this.localization, states = {
                        uploading: { text: localization.statusUploading },
                        uploaded: { text: localization.statusUploaded },
                        failed: { text: localization.statusFailed }
                    }, currentState = states[stateKey];
                if (currentState) {
                    $('span.k-file-state', fileEntry).text(currentState.text);
                }
            },
            _renderAction: function (actionClass, actionText, iconClass) {
                if (actionClass !== '') {
                    return $('<button type=\'button\' class=\'k-button k-upload-action\' aria-label=\'' + actionText + '\'>' + '<span class=\'k-icon ' + iconClass + ' ' + actionClass + '\' title=\'' + actionText + '\'></span>' + '</button>').on('focus', function () {
                        $(this).addClass('k-state-focused');
                    }).on('blur', function () {
                        $(this).removeClass('k-state-focused');
                    });
                } else {
                    return $('<button type=\'button\' class=\'k-button\'>' + actionText + '</button>');
                }
            },
            _clearFileAction: function (fileElement) {
                $('.k-upload-action', fileElement).empty().hide();
            },
            _onFileAction: function (e) {
                var that = this;
                if (!that.wrapper.hasClass('k-state-disabled')) {
                    var button = $(e.target).closest('.k-upload-action');
                    var icon = button.find('.k-icon');
                    var fileEntry = button.closest('.k-file');
                    var files = fileEntry.data('fileNames');
                    var hasValidationErrors = that._filesContainValidationErrors(files);
                    var eventArgs = {
                        files: files,
                        headers: {}
                    };
                    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, columns = options.columns;
                ui = this._widget = new kendo.ui.ColorPicker(ui, {
                    toolIcon: 'k-icon k-i-' + EditorUtils.getToolCssClass(options.name),
                    palette: palette,
                    columns: columns,
                    change: function () {
                        var color = ui.value();
                        if (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'
                            }
                        ]
                    });
                    this._toolBar.wrapper.off('keydown');
                    toolBarElement.before(templates.slider);
                    this._volumeButton = toolBarElement.find('.k-volume-button');
                    this._fullscreenButton = toolBarElement.find('.k-fullscreen-button');
                    this._volumeButton.attr('title', this.options.mute ? this.options.messages.unmute : this.options.messages.mute);
                    this._volumeButton.attr('aria-label', this.options.mute ? this.options.messages.unmute : this.options.messages.mute);
                    this._fullscreenButton.attr('title', this.options.messages.fullscreen);
                    this._fullscreenButton.attr('aria-label', this.options.messages.fullscreen);
                    toolBarElement.width('auto');
                    this._currentTimeElement = toolBarElement.find('.k-mediaplayer-currenttime');
                    this._durationElement = toolBarElement.find('.k-mediaplayer-duration');
                    this._playButton = toolBarElement.find('.k-play-button');
                    this._playButtonSpan = this._playButton.find('.k-i-play');
                    if (this.options.autoPlay) {
                        this._playStateToggle(true);
                    }
                    $([
                        this._volumeButton[0],
                        toolBarElement.find('.k-mediaplayer-volume-wrap')[0],
                        toolBarElement.find('.k-mediaplayer-quality-wrap')[0],
                        this._fullscreenButton[0]
                    ]).wrapAll('<div class=\'k-align-right\' />');
                    toolBarElement.find('.k-button').addClass('k-bare');
                }
            },
            _createDropDown: function () {
                var dropDownElement = this.wrapper.find(DOT + VIDEO_QUALITY);
                var media = this.media();
                if (typeof dropDownElement.data('kendoDropDownList') === 'undefined') {
                    this._dropDownSelectHandler = proxy(this._dropDownSelect, this);
                    this._dropDown = new ui.DropDownList(dropDownElement, {
                        dataTextField: 'quality',
                        dataValueField: 'url',
                        popup: {
                            position: 'bottom',
                            origin: 'top',
                            appendTo: this.wrapper
                        },
                        animation: {
                            open: {
                                effects: 'slideIn:up',
                                duration: 1
                            }
                        },
                        select: this._dropDownSelectHandler
                    });
                    if (media && isArray(media.source)) {
                        this._dropDown.setDataSource(media.source);
                        this._dropDown.select(0);
                    }
                    this._dropDown.wrapper.addClass('k-button k-bare');
                    this._dropDown.wrapper.attr('title', this.options.messages.quality).hide();
                    this._dropDown.wrapper.find('span.k-i-arrow-60-down').removeClass('k-i-arrow-60-down').addClass('k-icon k-i-hd');
                    this._dropDown.list.addClass('k-quality-list');
                }
            },
            _dropDownSelect: function (e) {
                if (this._currentIndex !== e.item.index()) {
                    this._currentIndex = e.item.index();
                    this._setPlayerUrl();
                }
            },
            _toolbarClick: function (e) {
                var target = $(e.target).children().first();
                var isPaused = target.hasClass(STATE_PLAY);
                if (!this.media()) {
                    return;
                }
                if (target.hasClass(STATE_PLAY) || target.hasClass(STATE_PAUSE)) {
                    if (isPaused) {
                        this.play();
                    } else {
                        this.pause();
                    }
                }
                if (target.hasClass(FULLSCREEN_ENTER) || target.hasClass(FULLSCREEN_EXIT)) {
                    if (this._isInFullScreen) {
                        target.removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                        this.fullScreen(false);
                    } else {
                        target.removeClass(FULLSCREEN_ENTER).addClass(FULLSCREEN_EXIT);
                        this.fullScreen(true);
                    }
                }
                if (target.hasClass(MUTE) || target.hasClass(LOW_VOLUME) || target.hasClass(HIGH_VOLUME)) {
                    var muted = this.mute();
                    this.mute(!muted);
                }
            },
            _sliderDragging: function () {
                if (!this.media()) {
                    return;
                }
                this._isDragging = true;
            },
            _sliderDragChange: function (e) {
                var that = this;
                var slider = e.sender;
                var tzOffset = timeZoneSec * 1000;
                if (!this.media()) {
                    return;
                }
                that._sliderChangeFired = true;
                that._isDragging = false;
                if (!this.options.forwardSeek && slider.value() > this._seekBarLastPosition) {
                    setTimeout(function () {
                        slider.value(that._seekBarLastPosition);
                    }, 1);
                } else if (this._youTubeVideo) {
                    that._ytmedia.seekTo(that._timeToSec(e.value - tzOffset));
                } else {
                    that._media.currentTime = that._timeToSec(e.value - tzOffset);
                }
                that.trigger(TIMECHANGE);
                that._preventPlay = true;
            },
            _changeVolumeButtonImage: function (volume) {
                var volumeButton = this._volumeButton;
                var volumeElement = volumeButton.find('span');
                var cssClass = volumeElement.attr('class');
                cssClass = cssClass.substring(0, cssClass.lastIndexOf(' '));
                if (volume === 0) {
                    volumeElement.attr('class', cssClass + ' ' + MUTE);
                    volumeButton.attr('title', this.options.messages.unmute);
                    volumeButton.attr('aria-label', this.options.messages.unmute);
                } else if (volume > 0 && volume < 51) {
                    volumeElement.attr('class', cssClass + ' ' + LOW_VOLUME);
                    volumeButton.attr('title', this.options.messages.mute);
                    volumeButton.attr('aria-label', this.options.messages.mute);
                } else {
                    volumeElement.attr('class', cssClass + ' ' + HIGH_VOLUME);
                    volumeButton.attr('title', this.options.messages.mute);
                    volumeButton.attr('aria-label', this.options.messages.mute);
                }
            },
            _volumeDragging: function (e) {
                if (!this.media()) {
                    return;
                }
                this.volume(e.value);
                this._changeVolumeButtonImage(e.value);
                this.trigger(VOLUMECHANGE);
            },
            _volumeChange: function (e) {
                if (!this.media()) {
                    return;
                }
                this.volume(e.value);
                this._changeVolumeButtonImage(e.value);
                this.trigger(VOLUMECHANGE);
            },
            _mediaTimeUpdate: function () {
                var currentTime = this._youTubeVideo ? this._ytmedia.getCurrentTime() : this._media.currentTime;
                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 {
                    if (kendo.support.mobileOS) {
                        this._uiDisplay(false);
                    }
                    this._media.play();
                }
                this._paused = false;
                this._playStateToggle(true);
                return this;
            },
            stop: function () {
                if (this._youTubeVideo && this._ytmedia) {
                    this._ytmedia.stopVideo();
                } else if (this._media && !this._youTubeVideo) {
                    if (kendo.support.mobileOS) {
                        this._uiDisplay(true);
                    }
                    this._media.pause();
                    this._media.currentTime = 0;
                }
                this._paused = true;
                this._playStateToggle(false);
                return this;
            },
            pause: function () {
                if (this._youTubeVideo) {
                    this._ytmedia.pauseVideo();
                } else {
                    if (kendo.support.mobileOS) {
                        this._uiDisplay(true);
                    }
                    this._media.pause();
                }
                this._paused = true;
                this._playStateToggle(false);
                this.trigger(PAUSE);
                return this;
            },
            toolbar: function () {
                return this._toolBar;
            },
            dropdown: function () {
                return this._dropDown;
            },
            titlebar: function () {
                return this._titleBar;
            },
            fullScreen: function (enterFullScreen) {
                if (typeof enterFullScreen === 'undefined') {
                    return this._isInFullScreen || false;
                }
                var element = this.element.get(0);
                if (enterFullScreen) {
                    this.element.addClass('k-mediaplayer-fullscreen');
                    if (element.requestFullscreen) {
                        element.requestFullscreen();
                    } else if (element.webkitRequestFullscreen) {
                        element.webkitRequestFullscreen();
                    } else if (element.mozRequestFullScreen) {
                        element.mozRequestFullScreen();
                    } else if (element.msRequestFullscreen) {
                        element.msRequestFullscreen();
                    }
                    this._isInFullScreen = true;
                } else {
                    if (document.cancelFullscreen) {
                        document.cancelFullscreen();
                    } else if (document.webkitCancelFullScreen) {
                        document.webkitCancelFullScreen();
                    } else if (document.mozCancelFullScreen) {
                        document.mozCancelFullScreen();
                    } else if (document.msCancelFullscreen) {
                        document.msCancelFullscreen();
                    } else if (document.exitFullscreen) {
                        document.exitFullscreen();
                    } else if (document.msExitFullscreen) {
                        document.msExitFullscreen();
                    }
                    this.element.removeClass('k-mediaplayer-fullscreen');
                    this._isInFullScreen = false;
                }
                this._slider.resize();
            },
            volume: function (value) {
                if (typeof value === 'undefined') {
                    return typeof this._volume !== 'undefined' ? this._volume : this._volume = this.options.volume;
                }
                this._volume = value;
                this.mute(value <= 0);
                if (this._youTubeVideo) {
                    this._ytmedia.setVolume(this._volume);
                } else {
                    this._media.volume = this._volume / 100;
                }
                this._volumeSlider.value(value);
            },
            mute: function (muted) {
                var currentState = this._youTubeVideo ? this._ytmedia && this._ytmedia.isMuted() : this._media && this._media.muted;
                if (typeof muted === 'undefined' || muted === currentState) {
                    return currentState;
                }
                if (this._youTubeVideo) {
                    if (muted) {
                        this._ytmedia.mute();
                    } else {
                        this._ytmedia.unMute();
                    }
                } else {
                    this._media.muted = muted;
                }
                if (muted) {
                    this._volumeSlider.value(0);
                } else {
                    this._volumeSlider.value(this._media && this._media.volume * 100 || this._ytmedia && this._ytmedia.getVolume());
                }
                this.trigger(VOLUMECHANGE);
                this._changeVolumeButtonImage(this._volumeSlider.value());
            },
            isEnded: function () {
                if (this._youTubeVideo) {
                    return this._ytmedia.getPlayerState() === 0;
                } else {
                    return this._media.ended;
                }
            },
            media: function (value) {
                var dropdown = this.dropdown();
                if (typeof value === 'undefined') {
                    return typeof this._mediaData !== 'undefined' ? this._mediaData : this._mediaData = this.options.media;
                }
                if (isArray(value.source)) {
                    dropdown.setDataSource(value.source);
                    dropdown.wrapper.show();
                } else {
                    dropdown.wrapper.hide();
                }
                this._mediaData = value;
                this._updateTitle();
                this._setPlayerUrl();
            },
            isPaused: function () {
                return this._paused;
            },
            isPlaying: function () {
                return !this.isEnded() && !this._paused;
            },
            _aria: function () {
                this.wrapper.attr('role', 'region');
            },
            _navigatable: function () {
                this._fullscreenHandler = proxy(this._fullscreen, this);
                $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange' + ns, this._fullscreenHandler);
                if (this.options.navigatable) {
                    this.wrapper.attr('tabIndex', 0);
                    this._keyDownHandler = proxy(this._keyDown, this);
                    this.wrapper.on('keydown' + ns, this._keyDownHandler);
                }
            },
            _fullscreen: function () {
                var isFullScreen = document.fullScreen || document.mozFullScreen || document.webkitIsFullScreen;
                this._uiDisplay(true);
                this._slider.resize();
                if (!isFullScreen) {
                    this.wrapper.find('span[class*="k-i-fullscreen"]').removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                    this.fullScreen(false);
                }
            },
            _keyDown: function (e) {
                e.preventDefault();
                var fsButton = this.wrapper.find('span[class*="k-i-fullscreen"]');
                if (e.keyCode === keys.SPACEBAR) {
                    if (this.isPlaying()) {
                        this.pause();
                    } else {
                        this.play();
                    }
                } else if (e.keyCode === keys.ENTER && !this._isInFullScreen) {
                    fsButton.removeClass(FULLSCREEN_ENTER).addClass(FULLSCREEN_EXIT);
                    this.fullScreen(true);
                } else if (e.keyCode === 77) {
                    var muted = this.mute();
                    this.mute(!muted);
                } else if (e.keyCode === keys.ESC && this._isInFullScreen) {
                    fsButton.removeClass(FULLSCREEN_EXIT).addClass(FULLSCREEN_ENTER);
                    this.fullScreen(false);
                }
            },
            _error: function () {
            },
            _progress: function () {
            }
        });
        ui.plugin(MediaPlayer);
    }(window.kendo.jQuery));
    return window.kendo;
}, typeof define === 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.pivotgrid', [
        'kendo.dom',
        'kendo.data'
    ], f);
}(function () {
    var __meta__ = {
        id: 'pivotgrid',
        name: 'PivotGrid',
        category: 'web',
        description: 'The PivotGrid widget is a data summarization tool.',
        depends: [
            'dom',
            'data',
            'data.xml',
            'sortable'
        ],
        features: [
            {
                id: 'pivotgrid-configurator',
                name: 'Configurator',
                description: 'The PivotConfigurator widget allows the user to select data slices displayed in PivotGrid',
                depends: ['pivot.configurator']
            },
            {
                id: 'pivotgrid-filtering',
                name: 'Filtering',
                description: 'Support for filtering',
                depends: ['pivot.fieldmenu']
            },
            {
                id: 'pivotgrid-excel-export',
                name: 'Excel export',
                description: 'Export pivot grid data as Excel spreadsheet',
                depends: ['ooxml']
            },
            {
                id: 'pivotgrid-pdf-export',
                name: 'PDF export',
                description: 'Export pivot grid data as PDF',
                depends: [
                    'pdf',
                    'drawing'
                ]
            },
            {
                id: 'mobile-scroller',
                name: 'Mobile scroller',
                description: 'Support for kinetic scrolling in mobile device',
                depends: ['mobile.scroller']
            }
        ]
    };
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui, Class = kendo.Class, Widget = ui.Widget, DataSource = kendo.data.DataSource, outerWidth = kendo._outerWidth, outerHeight = kendo._outerHeight, toString = {}.toString, identity = function (o) {
                return o;
            }, map = $.map, extend = $.extend, isFunction = kendo.isFunction, CHANGE = 'change', ERROR = 'error', MEASURES = 'Measures', PROGRESS = 'progress', STATERESET = 'stateReset', AUTO = 'auto', DIV = '<div/>', NS = '.kendoPivotGrid', ROW_TOTAL_KEY = '__row_total__', DATABINDING = 'dataBinding', DATABOUND = 'dataBound', EXPANDMEMBER = 'expandMember', COLLAPSEMEMBER = 'collapseMember', STATE_EXPANDED = 'k-i-collapse', STATE_COLLAPSED = 'k-i-expand', HEADER_TEMPLATE = '<span>#: data.member.caption || data.member.name #</span>', KPISTATUS_TEMPLATE = '<span class="k-icon k-i-#=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 current = tuples.shift();
            var counter = measuresLength;
            while (current) {
                if (current.name === MEASURES) {
                    counter += measuresLength - 1;
                } else if (current.children) {
                    [].push.apply(tuples, current.children);
                } else {
                    counter++;
                    [].push.apply(tuples, current.members);
                }
                current = tuples.shift();
            }
            return counter;
        }
        function mergeTuples(target, source, measures) {
            if (!source[0]) {
                return {
                    parsedRoot: null,
                    tuples: target,
                    memberIndex: 0,
                    index: 0
                };
            }
            var result = findExistingTuple(target, source[0]);
            if (!result.tuple) {
                return {
                    parsedRoot: null,
                    tuples: source,
                    memberIndex: 0,
                    index: 0
                };
            }
            var targetMembers = result.tuple.members;
            var sourceMembers = source[0].members;
            var memberIndex = -1;
            if (targetMembers.length !== sourceMembers.length) {
                return {
                    parsedRoot: null,
                    tuples: source,
                    memberIndex: 0,
                    index: 0
                };
            }
            for (var idx = 0, length = targetMembers.length; idx < length; idx++) {
                if (!targetMembers[idx].measure && sourceMembers[idx].children[0]) {
                    if (memberIndex == -1 && sourceMembers[idx].children.length) {
                        memberIndex = idx;
                    }
                    targetMembers[idx].children = sourceMembers[idx].children;
                }
            }
            measures = Math.max(measures.length, 1);
            return {
                parsedRoot: result.tuple,
                index: result.index * measures,
                memberIndex: memberIndex,
                tuples: target
            };
        }
        function equalTuples(first, second) {
            var equal = true;
            var idx, length;
            first = first.members;
            second = second.members;
            for (idx = 0, length = first.length; idx < length; idx++) {
                if (first[idx].measure || second[idx].measure) {
                    continue;
                }
                equal = equal && getName(first[idx]) === getName(second[idx]);
            }
            return equal;
        }
        function findExistingTuple(tuples, toFind) {
            var idx, length, tuple, found, counter = 0;
            var memberIndex, membersLength, member;
            for (idx = 0, length = tuples.length; idx < length; idx++) {
                tuple = tuples[idx];
                if (equalTuples(tuple, toFind)) {
                    return {
                        tuple: tuple,
                        index: counter
                    };
                }
                counter++;
                for (memberIndex = 0, membersLength = tuple.members.length; memberIndex < membersLength; memberIndex++) {
                    member = tuple.members[memberIndex];
                    if (member.measure) {
                        continue;
                    }
                    found = findExistingTuple(member.children, toFind);
                    counter += found.index;
                    if (found.tuple) {
                        return {
                            tuple: found.tuple,
                            index: counter
                        };
                    }
                }
            }
            return { index: counter };
        }
        function addMembers(members, map) {
            var member, i, len, path = '';
            for (i = 0, len = members.length; i < len; i++) {
                member = members[i];
                path += member.name;
                if (!map[path]) {
                    map[path] = member;
                }
            }
        }
        function findParentMember(tuple, map) {
            var members = tuple.members;
            var i, len, member, path = '';
            var parentPath = '';
            var parentMember;
            for (i = 0, len = members.length; i < len; i++) {
                member = members[i];
                if (parentMember) {
                    if (map[path + member.name]) {
                        path += member.name;
                        parentMember = map[path];
                        continue;
                    } else if (map[path + member.parentName]) {
                        return map[path + member.parentName];
                    } else if (map[parentPath + member.parentName]) {
                        return map[parentPath + member.parentName];
                    } else {
                        return map[parentPath];
                    }
                }
                path += member.name;
                parentMember = map[member.parentName];
                if (!parentMember) {
                    parentMember = map[path];
                    if (!parentMember) {
                        return null;
                    }
                }
                if (parentMember) {
                    parentPath += parentMember.name;
                }
            }
            return parentMember;
        }
        function measurePosition(tuple, measures) {
            if (measures.length === 0) {
                return -1;
            }
            var measure = measures[0];
            var members = tuple.members;
            for (var idx = 0, len = members.length; idx < len; idx++) {
                if (members[idx].name == measure.name) {
                    return idx;
                }
            }
        }
        function normalizeTupleMeasures(tuple, index) {
            if (index < 0) {
                return;
            }
            var member = {
                name: MEASURES,
                measure: true,
                children: [$.extend({
                        members: [],
                        dataIndex: tuple.dataIndex
                    }, tuple.members[index])]
            };
            tuple.members.splice(index, 1, member);
            tuple.dataIndex = undefined;
        }
        function parseSource(tuples, measures) {
            if (tuples.length < 1) {
                return [];
            }
            var result = [];
            var map = {};
            var measureIndex = measurePosition(tuples[0], measures);
            for (var i = 0; i < tuples.length; i++) {
                var tuple = tuples[i];
                tuple.dataIndex = i;
                normalizeTupleMeasures(tuple, measureIndex);
                var parentMember = findParentMember(tuple, map);
                if (parentMember) {
                    if (measureIndex < 0 || !parentMember.measure) {
                        parentMember.children.push(tuple);
                    } else {
                        parentMember.children.push(tuple.members[measureIndex].children[0]);
                    }
                } else {
                    result.push(tuple);
                }
                addMembers(tuple.members, map);
            }
            return result;
        }
        function prepareDataOnRows(tuples, data) {
            if (!tuples || !tuples.length) {
                return data;
            }
            var result = [];
            var indices = buildDataIndices(tuples);
            var rowsLength = indices.length;
            var columnsLength = Math.max(data.length / rowsLength, 1);
            var rowIndex, columnIndex, targetIndex, sourceIndex;
            var calcIndex;
            for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                targetIndex = columnsLength * rowIndex;
                sourceIndex = columnsLength * indices[rowIndex];
                for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                    calcIndex = parseInt(sourceIndex + columnIndex, 10);
                    result[parseInt(targetIndex + columnIndex, 10)] = data[calcIndex] || {
                        value: '',
                        fmtValue: '',
                        ordinal: calcIndex
                    };
                }
            }
            return result;
        }
        function prepareDataOnColumns(tuples, data) {
            if (!tuples || !tuples.length) {
                return data;
            }
            var result = [];
            var indices = buildDataIndices(tuples);
            var columnsLength = indices.length;
            var rowsLength = Math.max(data.length / columnsLength, 1);
            var columnIndex, rowIndex, dataIndex, calcIndex;
            for (rowIndex = 0; rowIndex < rowsLength; rowIndex++) {
                dataIndex = columnsLength * rowIndex;
                for (columnIndex = 0; columnIndex < columnsLength; columnIndex++) {
                    calcIndex = indices[columnIndex] + dataIndex;
                    result[dataIndex + columnIndex] = data[calcIndex] || {
                        value: '',
                        fmtValue: '',
                        ordinal: calcIndex
                    };
                }
            }
            return result;
        }
        function buildDataIndices(tuples) {
            tuples = tuples.slice();
            var result = [];
            var tuple = tuples.shift();
            var idx, length, spliceIndex, children, member;
            while (tuple) {
                if (tuple.dataIndex !== undefined) {
                    result.push(tuple.dataIndex);
                }
                spliceIndex = 0;
                for (idx = 0, length = tuple.members.length; idx < length; idx++) {
                    member = tuple.members[idx];
                    children = member.children;
                    if (member.measure) {
                        [].splice.apply(tuples, [
                            0,
                            0
                        ].concat(children));
                    } else {
                        [].splice.apply(tuples, [
                            spliceIndex,
                            0
                        ].concat(children));
                    }
                    spliceIndex += children.length;
                }
                tuple = tuples.shift();
            }
            return result;
        }
        PivotDataSource.create = function (options) {
            options = options && options.push ? { data: options } : options;
            var dataSource = options || {}, data = dataSource.data;
            dataSource.data = data;
            if (!(dataSource instanceof PivotDataSource) && dataSource instanceof kendo.data.DataSource) {
                throw new Error('Incorrect DataSource type. Only PivotDataSource instances are supported');
            }
            return dataSource instanceof PivotDataSource ? dataSource : new PivotDataSource(dataSource);
        };
        function baseHierarchyPath(memberName) {
            var parts = memberName.split('.');
            if (parts.length > 2) {
                return parts[0] + '.' + parts[1];
            }
            return memberName;
        }
        function expandMemberDescriptor(names, sort) {
            var idx = names.length - 1;
            var name = names[idx];
            var sortDescriptor;
            sortDescriptor = sortDescriptorForMember(sort, name);
            if (sortDescriptor && sortDescriptor.dir) {
                name = 'ORDER(' + name + '.Children,' + sortDescriptor.field + '.CurrentMember.MEMBER_CAPTION,' + sortDescriptor.dir + ')';
            } else {
                name += '.Children';
            }
            names[idx] = name;
            return names;
        }
        function sortDescriptorForMember(sort, member) {
            for (var idx = 0, length = sort.length; idx < length; idx++) {
                if (member.indexOf(sort[idx].field) === 0) {
                    return sort[idx];
                }
            }
            return null;
        }
        function crossJoin(names) {
            var result = 'CROSSJOIN({';
            var r;
            if (names.length > 2) {
                r = names.pop();
                result += crossJoin(names);
            } else {
                result += names.shift();
                r = names.pop();
            }
            result += '},{';
            result += r;
            result += '})';
            return result;
        }
        function crossJoinCommand(members, measures) {
            var tmp = members.slice(0);
            if (measures.length > 1) {
                tmp.push('{' + measureNames(measures).join(',') + '}');
            }
            return crossJoin(tmp);
        }
        function measureNames(measures) {
            var idx = 0;
            var length = measures.length;
            var result = [];
            var measure;
            for (; idx < length; idx++) {
                measure = measures[idx];
                result.push(measure.name !== undefined ? measure.name : measure);
            }
            return result;
        }
        function getName(name) {
            name = name.name || name;
            if (toString.call(name) === '[object Array]') {
                name = name[name.length - 1];
            }
            return name;
        }
        function getRootNames(members) {
            var length = members.length;
            var names = [];
            var idx = 0;
            for (; idx < length; idx++) {
                names.push(members[idx].name[0]);
            }
            return names;
        }
        function mapNames(names, rootNames) {
            var name;
            var rootName;
            var j;
            var idx = 0;
            var length = names.length;
            var rootLength = rootNames.length;
            rootNames = rootNames.slice(0);
            for (; idx < length; idx++) {
                name = names[idx];
                for (j = 0; j < rootLength; j++) {
                    rootName = baseHierarchyPath(rootNames[j]);
                    if (name.indexOf(rootName) !== -1) {
                        rootNames[j] = name;
                        break;
                    }
                }
            }
            return {
                names: rootNames,
                expandedIdx: j,
                uniquePath: rootNames.slice(0, j + 1).join('')
            };
        }
        function parseDescriptors(members) {
            var expanded = [];
            var child = [];
            var root = [];
            var member;
            var j, l;
            var idx = 0;
            var length = members.length;
            var name;
            var hierarchyName;
            var found;
            for (; idx < length; idx++) {
                member = members[idx];
                name = member.name;
                found = false;
                if (toString.call(name) !== '[object Array]') {
                    member.name = name = [name];
                }
                if (name.length > 1) {
                    child.push(member);
                } else {
                    hierarchyName = baseHierarchyPath(name[0]);
                    for (j = 0, l = root.length; j < l; j++) {
                        if (root[j].name[0].indexOf(hierarchyName) === 0) {
                            found = true;
                            break;
                        }
                    }
                    if (!found) {
                        root.push(member);
                    }
                    if (member.expand) {
                        expanded.push(member);
                    }
                }
            }
            expanded = expanded.concat(child);
            return {
                root: root,
                expanded: expanded
            };
        }
        function serializeMembers(members, measures, sort) {
            var command = '';
            members = members || [];
            var expanded = parseDescriptors(members);
            var root = expanded.root;
            var rootNames = getRootNames(root);
            var crossJoinCommands = [];
            expanded = expanded.expanded;
            var length = expanded.length;
            var idx = 0;
            var memberName;
            var names = [];
            if (rootNames.length > 1 || measures.length > 1) {
                crossJoinCommands.push(crossJoinCommand(rootNames, measures));
                for (; idx < length; idx++) {
                    memberName = expandMemberDescriptor(expanded[idx].name, sort);
                    names = mapNames(memberName, rootNames).names;
                    crossJoinCommands.push(crossJoinCommand(names, measures));
                }
                command += crossJoinCommands.join(',');
            } else {
                for (; idx < length; idx++) {
                    memberName = expandMemberDescriptor(expanded[idx].name, sort);
                    names.push(memberName[0]);
                }
                command += rootNames.concat(names).join(',');
            }
            return command;
        }
        var filterFunctionFormats = {
            contains: ', InStr({0}.CurrentMember.MEMBER_CAPTION,"{1}") > 0',
            doesnotcontain: ', InStr({0}.CurrentMember.MEMBER_CAPTION,"{1}")',
            startswith: ', Left({0}.CurrentMember.MEMBER_CAPTION,Len("{1}"))="{1}"',
            endswith: ', Right({0}.CurrentMember.MEMBER_CAPTION,Len("{1}"))="{1}"',
            eq: ', {0}.CurrentMember.MEMBER_CAPTION = "{1}"',
            neq: ', {0}.CurrentMember.MEMBER_CAPTION = "{1}"'
        };
        function serializeExpression(expression) {
            var command = '';
            var value = expression.value;
            var field = expression.field;
            var operator = expression.operator;
            if (operator == 'in') {
                command += '{';
                command += value;
                command += '}';
            } else {
                command += operator == 'neq' || operator == 'doesnotcontain' ? '-' : '';
                command += 'Filter(';
                command += field + '.MEMBERS';
                command += kendo.format(filterFunctionFormats[operator], field, value);
                command += ')';
            }
            return command;
        }
        function serializeFilters(filter, cube) {
            var command = '', current;
            var filters = filter.filters;
            var length = filters.length;
            var idx;
            for (idx = length - 1; idx >= 0; idx--) {
                current = 'SELECT (';
                current += serializeExpression(filters[idx]);
                current += ') ON 0';
                if (idx == length - 1) {
                    current += ' FROM [' + cube + ']';
                    command = current;
                } else {
                    command = current + ' FROM ( ' + command + ' )';
                }
            }
            return command;
        }
        function serializeOptions(parentTagName, options, capitalize) {
            var result = '';
            if (options) {
                result += '<' + parentTagName + '>';
                var value;
                for (var key in options) {
                    value = options[key];
                    if (capitalize) {
                        key = key.replace(/([A-Z]+(?=$|[A-Z][a-z])|[A-Z]?[a-z]+)/g, '$1_').toUpperCase().replace(/_$/, '');
                    }
                    result += '<' + key + '>' + value + '</' + key + '>';
                }
                result += '</' + parentTagName + '>';
            } else {
                result += '<' + parentTagName + '/>';
            }
            return result;
        }
        var xmlaDiscoverCommands = {
            schemaCubes: 'MDSCHEMA_CUBES',
            schemaCatalogs: 'DBSCHEMA_CATALOGS',
            schemaMeasures: 'MDSCHEMA_MEASURES',
            schemaDimensions: 'MDSCHEMA_DIMENSIONS',
            schemaHierarchies: 'MDSCHEMA_HIERARCHIES',
            schemaLevels: 'MDSCHEMA_LEVELS',
            schemaMembers: 'MDSCHEMA_MEMBERS',
            schemaKPIs: 'MDSCHEMA_KPIS'
        };
        var convertersMap = {
            read: function (options) {
                var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Execute xmlns="urn:schemas-microsoft-com:xml-analysis"><Command><Statement>';
                command += 'SELECT NON EMPTY {';
                var columns = options.columns || [];
                var rows = options.rows || [];
                var measures = options.measures || [];
                var measuresRowAxis = options.measuresAxis === 'rows';
                var sort = options.sort || [];
                if (!columns.length && rows.length && (!measures.length || measures.length && measuresRowAxis)) {
                    columns = rows;
                    rows = [];
                    measuresRowAxis = false;
                }
                if (!columns.length && !rows.length) {
                    measuresRowAxis = false;
                }
                if (columns.length) {
                    command += serializeMembers(columns, !measuresRowAxis ? measures : [], sort);
                } else if (measures.length && !measuresRowAxis) {
                    command += measureNames(measures).join(',');
                }
                command += '} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON COLUMNS';
                if (rows.length || measuresRowAxis && measures.length > 1) {
                    command += ', NON EMPTY {';
                    if (rows.length) {
                        command += serializeMembers(rows, measuresRowAxis ? measures : [], sort);
                    } else {
                        command += measureNames(measures).join(',');
                    }
                    command += '} DIMENSION PROPERTIES CHILDREN_CARDINALITY, PARENT_UNIQUE_NAME ON ROWS';
                }
                if (options.filter) {
                    command += ' FROM ';
                    command += '(';
                    command += serializeFilters(options.filter, options.connection.cube);
                    command += ')';
                } else {
                    command += ' FROM [' + options.connection.cube + ']';
                }
                if (measures.length == 1 && columns.length) {
                    command += ' WHERE (' + measureNames(measures).join(',') + ')';
                }
                command += '</Statement></Command><Properties><PropertyList><Catalog>' + options.connection.catalog + '</Catalog><Format>Multidimensional</Format></PropertyList></Properties></Execute></Body></Envelope>';
                return command.replace(/\&/g, '&amp;');
            },
            discover: function (options) {
                options = options || {};
                var command = '<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"><Header/><Body><Discover xmlns="urn:schemas-microsoft-com:xml-analysis">';
                command += '<RequestType>' + (xmlaDiscoverCommands[options.command] || options.command) + '</RequestType>';
                command += '<Restrictions>' + serializeOptions('RestrictionList', options.restrictions, true) + '</Restrictions>';
                if (options.connection && options.connection.catalog) {
                    options.properties = $.extend({}, { Catalog: options.connection.catalog }, options.properties);
                }
                command += '<Properties>' + serializeOptions('PropertyList', options.properties) + '</Properties>';
                command += '</Discover></Body></Envelope>';
                return command;
            }
        };
        var XmlaTransport = kendo.data.RemoteTransport.extend({
            init: function (options) {
                var originalOptions = options;
                options = this.options = extend(true, {}, this.options, options);
                kendo.data.RemoteTransport.call(this, options);
                if (isFunction(originalOptions.discover)) {
                    this.discover = originalOptions.discover;
                } else if (typeof originalOptions.discover === 'string') {
                    this.options.discover = { url: originalOptions.discover };
                } else if (!originalOptions.discover) {
                    this.options.discover = this.options.read;
                }
            },
            setup: function (options, type) {
                options.data = options.data || {};
                $.extend(true, options.data, { connection: this.options.connection });
                return kendo.data.RemoteTransport.fn.setup.call(this, options, type);
            },
            options: {
                read: {
                    dataType: 'text',
                    contentType: 'text/xml',
                    type: 'POST'
                },
                discover: {
                    dataType: 'text',
                    contentType: 'text/xml',
                    type: 'POST'
                },
                parameterMap: function (options, type) {
                    return convertersMap[type](options, type);
                }
            },
            discover: function (options) {
                return $.ajax(this.setup(options, 'discover'));
            }
        });
        function asArray(object) {
            if (object == null) {
                return [];
            }
            var type = toString.call(object);
            if (type !== '[object Array]') {
                return [object];
            }
            return object;
        }
        function translateAxis(axis) {
            var result = { tuples: [] };
            var tuples = asArray(kendo.getter('Tuples.Tuple', true)(axis));
            var captionGetter = kendo.getter('Caption[\'#text\']');
            var unameGetter = kendo.getter('UName[\'#text\']');
            var levelNameGetter = kendo.getter('LName[\'#text\']');
            var levelNumGetter = kendo.getter('LNum[\'#text\']');
            var childrenGetter = kendo.getter('CHILDREN_CARDINALITY[\'#text\']', true);
            var hierarchyGetter = kendo.getter('[\'@Hierarchy\']');
            var parentNameGetter = kendo.getter('PARENT_UNIQUE_NAME[\'#text\']', true);
            for (var idx = 0; idx < tuples.length; idx++) {
                var members = [];
                var member = asArray(tuples[idx].Member);
                for (var memberIdx = 0; memberIdx < member.length; memberIdx++) {
                    members.push({
                        children: [],
                        caption: captionGetter(member[memberIdx]),
                        name: unameGetter(member[memberIdx]),
                        levelName: levelNameGetter(member[memberIdx]),
                        levelNum: levelNumGetter(member[memberIdx]),
                        hasChildren: parseInt(childrenGetter(member[memberIdx]), 10) > 0,
                        parentName: parentNameGetter(member[memberIdx]),
                        hierarchy: hierarchyGetter(member[memberIdx])
                    });
                }
                result.tuples.push({ members: members });
            }
            return result;
        }
        var schemaDataReaderMap = {
            cubes: {
                name: kendo.getter('CUBE_NAME[\'#text\']', true),
                caption: kendo.getter('CUBE_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                type: kendo.getter('CUBE_TYPE[\'#text\']', true)
            },
            catalogs: {
                name: kendo.getter('CATALOG_NAME[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true)
            },
            measures: {
                name: kendo.getter('MEASURE_NAME[\'#text\']', true),
                caption: kendo.getter('MEASURE_CAPTION[\'#text\']', true),
                uniqueName: kendo.getter('MEASURE_UNIQUE_NAME[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                aggregator: kendo.getter('MEASURE_AGGREGATOR[\'#text\']', true),
                groupName: kendo.getter('MEASUREGROUP_NAME[\'#text\']', true),
                displayFolder: kendo.getter('MEASURE_DISPLAY_FOLDER[\'#text\']', true),
                defaultFormat: kendo.getter('DEFAULT_FORMAT_STRING[\'#text\']', true)
            },
            kpis: {
                name: kendo.getter('KPI_NAME[\'#text\']', true),
                caption: kendo.getter('KPI_CAPTION[\'#text\']', true),
                value: kendo.getter('KPI_VALUE[\'#text\']', true),
                goal: kendo.getter('KPI_GOAL[\'#text\']', true),
                status: kendo.getter('KPI_STATUS[\'#text\']', true),
                trend: kendo.getter('KPI_TREND[\'#text\']', true),
                statusGraphic: kendo.getter('KPI_STATUS_GRAPHIC[\'#text\']', true),
                trendGraphic: kendo.getter('KPI_TREND_GRAPHIC[\'#text\']', true),
                description: kendo.getter('KPI_DESCRIPTION[\'#text\']', true),
                groupName: kendo.getter('MEASUREGROUP_NAME[\'#text\']', true)
            },
            dimensions: {
                name: kendo.getter('DIMENSION_NAME[\'#text\']', true),
                caption: kendo.getter('DIMENSION_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                defaultHierarchy: kendo.getter('DEFAULT_HIERARCHY[\'#text\']', true),
                type: kendo.getter('DIMENSION_TYPE[\'#text\']', true)
            },
            hierarchies: {
                name: kendo.getter('HIERARCHY_NAME[\'#text\']', true),
                caption: kendo.getter('HIERARCHY_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                displayFolder: kendo.getter('HIERARCHY_DISPLAY_FOLDER[\'#text\']', true),
                origin: kendo.getter('HIERARCHY_ORIGIN[\'#text\']', true),
                defaultMember: kendo.getter('DEFAULT_MEMBER[\'#text\']', true)
            },
            levels: {
                name: kendo.getter('LEVEL_NAME[\'#text\']', true),
                caption: kendo.getter('LEVEL_CAPTION[\'#text\']', true),
                description: kendo.getter('DESCRIPTION[\'#text\']', true),
                uniqueName: kendo.getter('LEVEL_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                displayFolder: kendo.getter('LEVEL_DISPLAY_FOLDER[\'#text\']', true),
                orderingProperty: kendo.getter('LEVEL_ORDERING_PROPERTY[\'#text\']', true),
                origin: kendo.getter('LEVEL_ORIGIN[\'#text\']', true),
                hierarchyUniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true)
            },
            members: {
                name: kendo.getter('MEMBER_NAME[\'#text\']', true),
                caption: kendo.getter('MEMBER_CAPTION[\'#text\']', true),
                uniqueName: kendo.getter('MEMBER_UNIQUE_NAME[\'#text\']', true),
                dimensionUniqueName: kendo.getter('DIMENSION_UNIQUE_NAME[\'#text\']', true),
                hierarchyUniqueName: kendo.getter('HIERARCHY_UNIQUE_NAME[\'#text\']', true),
                levelUniqueName: kendo.getter('LEVEL_UNIQUE_NAME[\'#text\']', true),
                childrenCardinality: kendo.getter('CHILDREN_CARDINALITY[\'#text\']', true)
            }
        };
        var xmlaReaderMethods = [
            'axes',
            'catalogs',
            'cubes',
            'dimensions',
            'hierarchies',
            'levels',
            'measures'
        ];
        var XmlaDataReader = kendo.data.XmlDataReader.extend({
            init: function (options) {
                kendo.data.XmlDataReader.call(this, options);
                this._extend(options);
            },
            _extend: function (options) {
                var idx = 0;
                var length = xmlaReaderMethods.length;
                var methodName;
                var option;
                for (; idx < length; idx++) {
                    methodName = xmlaReaderMethods[idx];
                    option = options[methodName];
                    if (option && option !== identity) {
                        this[methodName] = option;
                    }
                }
            },
            parse: function (xml) {
                var result = kendo.data.XmlDataReader.fn.parse(xml.replace(/<(\/?)(\w|-)+:/g, '<$1'));
                return kendo.getter('[\'Envelope\'][\'Body\']', true)(result);
            },
            errors: function (root) {
                var fault = kendo.getter('[\'Fault\']', true)(root);
                if (fault) {
                    return [{
                            faultstring: kendo.getter('faultstring[\'#text\']', true)(fault),
                            faultcode: kendo.getter('faultcode[\'#text\']', true)(fault)
                        }];
                }
                return null;
            },
            axes: function (root) {
                root = kendo.getter('ExecuteResponse["return"].root', true)(root);
                var axes = asArray(kendo.getter('Axes.Axis', true)(root));
                var axis;
                var result = {
                    columns: {},
                    rows: {}
                };
                for (var idx = 0; idx < axes.length; idx++) {
                    axis = axes[idx];
                    if (axis['@name'].toLowerCase() !== 'sliceraxis') {
                        if (!result.columns.tuples) {
                            result.columns = translateAxis(axis);
                        } else {
                            result.rows = translateAxis(axis);
                        }
                    }
                }
                return result;
            },
            data: function (root) {
                root = kendo.getter('ExecuteResponse["return"].root', true)(root);
                var cells = asArray(kendo.getter('CellData.Cell', true)(root));
                var result = [];
                var ordinalGetter = kendo.getter('[\'@CellOrdinal\']');
                var valueGetter = kendo.getter('Value[\'#text\']');
                var fmtValueGetter = kendo.getter('FmtValue[\'#text\']');
                for (var idx = 0; idx < cells.length; idx++) {
                    result.push({
                        value: valueGetter(cells[idx]),
                        fmtValue: fmtValueGetter(cells[idx]),
                        ordinal: parseInt(ordinalGetter(cells[idx]), 10)
                    });
                }
                return result;
            },
            _mapSchema: function (root, getters) {
                root = kendo.getter('DiscoverResponse["return"].root', true)(root);
                var rows = asArray(kendo.getter('row', true)(root));
                var result = [];
                for (var idx = 0; idx < rows.length; idx++) {
                    var obj = {};
                    for (var key in getters) {
                        obj[key] = getters[key](rows[idx]);
                    }
                    result.push(obj);
                }
                return result;
            },
            measures: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.measures);
            },
            kpis: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.kpis);
            },
            hierarchies: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.hierarchies);
            },
            levels: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.levels);
            },
            dimensions: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.dimensions);
            },
            cubes: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.cubes);
            },
            catalogs: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.catalogs);
            },
            members: function (root) {
                return this._mapSchema(root, schemaDataReaderMap.members);
            }
        });
        extend(true, kendo.data, {
            PivotDataSource: PivotDataSource,
            XmlaTransport: XmlaTransport,
            XmlaDataReader: XmlaDataReader,
            PivotCubeBuilder: PivotCubeBuilder,
            transports: { xmla: XmlaTransport },
            readers: { xmla: XmlaDataReader }
        });
        var sortExpr = function (expressions, name) {
            if (!expressions) {
                return null;
            }
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field === name) {
                    return expressions[idx];
                }
            }
            return null;
        };
        var removeExpr = function (expressions, name) {
            var result = [];
            for (var idx = 0, length = expressions.length; idx < length; idx++) {
                if (expressions[idx].field !== name) {
                    result.push(expressions[idx]);
                }
            }
            return result;
        };
        kendo.ui.PivotSettingTarget = Widget.extend({
            init: function (element, options) {
                var that = this;
                Widget.fn.init.call(that, element, options);
                that.element.addClass('k-pivot-setting');
                that.dataSource = kendo.data.PivotDataSource.create(options.dataSource);
                that._refreshHandler = $.proxy(that.refresh, that);
                that.dataSource.first(CHANGE, that._refreshHandler);
                if (!options.template) {
                    that.options.template = '<div data-' + kendo.ns + 'name="${data.name || data}">${data.name || data}' + (that.options.enabled ? '<a class="k-button k-button-icon k-bare"><span class="k-icon k-i-close k-setting-delete"></span></a>' : '') + '</div>';
                }
                that.template = kendo.template(that.options.template);
                that.emptyTemplate = kendo.template(that.options.emptyTemplate);
                that._sortable();
                that.element.on('click' + NS, '.k-button,.k-item', function (e) {
                    var target = $(e.target);
                    var name = target.closest('[' + kendo.attr('name') + ']').attr(kendo.attr('name'));
                    if (!name) {
                        return;
                    }
                    if (target.hasClass('k-i-close')) {
                        that.remove(name);
                    } else if (that.options.sortable && target[0] === e.currentTarget) {
                        that.sort({
                            field: name,
                            dir: target.find('.k-i-sort-asc-sm')[0] ? 'desc' : 'asc'
                        });
                    }
                });
                if (options.filterable || options.sortable) {
                    that.fieldMenu = new ui.PivotFieldMenu(that.element, {
                        messages: that.options.messages.fieldMenu,
                        filter: '.k-setting-fieldmenu',
                        filterable: options.filterable,
                        sortable: options.sortable,
                        dataSource: that.dataSource
                    });
                }
                that.refresh();
            },
            options: {
                name: 'PivotSettingTarget',
                template: null,
                filterable: false,
                sortable: false,
                emptyTemplate: '<div class=\'k-empty\'>${data}</div>',
                setting: 'columns',
                enabled: true,
                messages: { empty: 'Drop Fields Here' }
            },
            setDataSource: function (dataSource) {
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                this.dataSource = this.options.dataSource = dataSource;
                if (this.fieldMenu) {
                    this.fieldMenu.setDataSource(dataSource);
                }
                dataSource.first(CHANGE, this._refreshHandler);
                this.refresh();
            },
            _sortable: function () {
                var that = this;
                if (that.options.enabled) {
                    this.sortable = this.element.kendoSortable({
                        connectWith: this.options.connectWith,
                        hint: that.options.hint,
                        cursor: 'move',
                        start: function (e) {
                            e.item.focus().blur();
                        },
                        change: function (e) {
                            var name = e.item.attr(kendo.attr('name'));
                            if (e.action == 'receive') {
                                that.add(name);
                            } else if (e.action == 'remove') {
                                that.remove(name);
                            } else if (e.action == 'sort') {
                                that.move(name, e.newIndex);
                            }
                        }
                    }).data('kendoSortable');
                }
            },
            _indexOf: function (name, items) {
                var idx, length, index = -1;
                for (idx = 0, length = items.length; idx < length; idx++) {
                    if (getName(items[idx]) === name) {
                        index = idx;
                        break;
                    }
                }
                return index;
            },
            _isKPI: function (data) {
                return data.type === 'kpi' || data.measure;
            },
            validate: function (data) {
                var isMeasure = data.type == 2 || 'aggregator' in data || this._isKPI(data);
                if (isMeasure) {
                    return this.options.setting === 'measures';
                }
                if (this.options.setting === 'measures') {
                    return isMeasure;
                }
                var items = this.dataSource[this.options.setting]();
                var name = data.defaultHierarchy || data.uniqueName;
                if (this._indexOf(name, items) > -1) {
                    return false;
                }
                items = this.dataSource[this.options.setting === 'columns' ? 'rows' : 'columns']();
                if (this._indexOf(name, items) > -1) {
                    return false;
                }
                return true;
            },
            add: function (name) {
                var items = this.dataSource[this.options.setting]();
                var i, l;
                name = $.isArray(name) ? name.slice(0) : [name];
                for (i = 0, l = name.length; i < l; i++) {
                    if (this._indexOf(name[i], items) !== -1) {
                        name.splice(i, 1);
                        i -= 1;
                        l -= 1;
                    }
                }
                if (name.length) {
                    items = items.concat(name);
                    this.dataSource[this.options.setting](items);
                }
            },
            move: function (name, index) {
                var items = this.dataSource[this.options.setting]();
                var idx = this._indexOf(name, items);
                if (idx > -1) {
                    name = items.splice(idx, 1)[0];
                    items.splice(index, 0, name);
                    this.dataSource[this.options.setting](items);
                }
            },
            remove: function (name) {
                var items = this.dataSource[this.options.setting]();
                var idx = this._indexOf(name, items);
                var sortExpressions = this.dataSource.sort();
                var filter = this.dataSource.filter();
                if (idx > -1) {
                    if (filter) {
                        filter.filters = removeExpr(filter.filters, name);
                        this.dataSource._filter.filters = filter.filters;
                        if (!filter.filters.length) {
                            this.dataSource._filter = null;
                        }
                    }
                    if (sortExpressions) {
                        sortExpressions = removeExpr(sortExpressions, name);
                        this.dataSource._sort = sortExpressions;
                    }
                    items.splice(idx, 1);
                    this.dataSource[this.options.setting](items);
                }
            },
            sort: function (expr) {
                var sortable = this.options.sortable;
                var allowUnsort = sortable === true || sortable.allowUnsort;
                var skipExpr = allowUnsort && expr.dir === 'asc';
                var expressions = this.dataSource.sort() || [];
                var result = removeExpr(expressions, expr.field);
                if (skipExpr && expressions.length !== result.length) {
                    expr = null;
                }
                if (expr) {
                    result.push(expr);
                }
                this.dataSource.sort(result);
            },
            refresh: function () {
                var html = '';
                var items = this.dataSource[this.options.setting]();
                var length = items.length;
                var idx = 0;
                var item;
                if (length) {
                    for (; idx < length; idx++) {
                        item = items[idx];
                        item = item.name === undefined ? { name: item } : item;
                        html += this.template(extend({ sortIcon: this._sortIcon(item.name) }, item));
                    }
                } else {
                    html = this.emptyTemplate(this.options.messages.empty);
                }
                this.element.html(html);
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.dataSource.unbind(CHANGE, this._refreshHandler);
                this.element.off(NS);
                if (this.sortable) {
                    this.sortable.destroy();
                }
                if (this.fieldMenu) {
                    this.fieldMenu.destroy();
                }
                this.element = null;
                this._refreshHandler = null;
            },
            _sortIcon: function (name) {
                var expressions = this.dataSource.sort();
                var expr = sortExpr(expressions, getName(name));
                var icon = '';
                if (expr) {
                    icon = 'k-i-sort-' + expr.dir;
                }
                return icon;
            }
        });
        var PivotGrid = Widget.extend({
            init: function (element, options) {
                var that = this;
                var columnBuilder;
                var rowBuilder;
                Widget.fn.init.call(that, element, options);
                that._dataSource();
                that._bindConfigurator();
                that._wrapper();
                that._createLayout();
                that._columnBuilder = columnBuilder = new ColumnBuilder();
                that._rowBuilder = rowBuilder = new RowBuilder();
                that._contentBuilder = new ContentBuilder();
                that._templates();
                that.columnsHeader.add(that.rowsHeader).on('click', 'span.k-icon', function () {
                    var button = $(this);
                    var builder = columnBuilder;
                    var action = 'expandColumn';
                    var eventName;
                    var path = button.attr(kendo.attr('path'));
                    var eventArgs = {
                        axis: 'columns',
                        path: $.parseJSON(path)
                    };
                    if (button.parent().is('td')) {
                        builder = rowBuilder;
                        action = 'expandRow';
                        eventArgs.axis = 'rows';
                    }
                    var expanded = button.hasClass(STATE_EXPANDED);
                    var metadata = builder.metadata[path];
                    var request = metadata.expanded === undefined;
                    eventName = expanded ? COLLAPSEMEMBER : EXPANDMEMBER;
                    eventArgs.childrenLoaded = metadata.maxChildren > metadata.children;
                    if (that.trigger(eventName, eventArgs)) {
                        return;
                    }
                    builder.metadata[path].expanded = !expanded;
                    button.toggleClass(STATE_EXPANDED, !expanded).toggleClass(STATE_COLLAPSED, expanded);
                    if (!expanded && request) {
                        that.dataSource[action](eventArgs.path);
                    } else {
                        that.refresh();
                    }
                });
                that._scrollable();
                if (that.options.autoBind) {
                    that.dataSource.fetch();
                }
                kendo.notify(that);
            },
            events: [
                DATABINDING,
                DATABOUND,
                EXPANDMEMBER,
                COLLAPSEMEMBER
            ],
            options: {
                name: 'PivotGrid',
                autoBind: true,
                reorderable: true,
                filterable: false,
                sortable: false,
                height: null,
                columnWidth: 100,
                configurator: '',
                columnHeaderTemplate: null,
                rowHeaderTemplate: null,
                dataCellTemplate: null,
                kpiStatusTemplate: null,
                kpiTrendTemplate: null,
                messages: {
                    measureFields: 'Drop Data Fields Here',
                    columnFields: 'Drop Column Fields Here',
                    rowFields: 'Drop Rows Fields Here'
                }
            },
            _templates: function () {
                var columnTemplate = this.options.columnHeaderTemplate;
                var rowTemplate = this.options.rowHeaderTemplate;
                var dataTemplate = this.options.dataCellTemplate;
                var kpiStatusTemplate = this.options.kpiStatusTemplate;
                var kpiTrendTemplate = this.options.kpiTrendTemplate;
                this._columnBuilder.template = kendo.template(columnTemplate || HEADER_TEMPLATE, { useWithBlock: !!columnTemplate });
                this._contentBuilder.dataTemplate = kendo.template(dataTemplate || DATACELL_TEMPLATE, { useWithBlock: !!dataTemplate });
                this._contentBuilder.kpiStatusTemplate = kendo.template(kpiStatusTemplate || KPISTATUS_TEMPLATE, { useWithBlock: !!kpiStatusTemplate });
                this._contentBuilder.kpiTrendTemplate = kendo.template(kpiTrendTemplate || KPITREND_TEMPLATE, { useWithBlock: !!kpiTrendTemplate });
                this._rowBuilder.template = kendo.template(rowTemplate || HEADER_TEMPLATE, { useWithBlock: !!rowTemplate });
            },
            _bindConfigurator: function () {
                var configurator = this.options.configurator;
                if (configurator) {
                    $(configurator).kendoPivotConfigurator('setDataSource', this.dataSource);
                }
            },
            cellInfoByElement: function (element) {
                element = $(element);
                return this.cellInfo(element.index(), element.parent('tr').index());
            },
            cellInfo: function (columnIndex, rowIndex) {
                var contentBuilder = this._contentBuilder;
                var columnInfo = contentBuilder.columnIndexes[columnIndex || 0];
                var rowInfo = contentBuilder.rowIndexes[rowIndex || 0];
                var dataIndex;
                if (!columnInfo || !rowInfo) {
                    return null;
                }
                dataIndex = rowInfo.index * contentBuilder.rowLength + columnInfo.index;
                return {
                    columnTuple: columnInfo.tuple,
                    rowTuple: rowInfo.tuple,
                    measure: columnInfo.measure || rowInfo.measure,
                    dataItem: this.dataSource.view()[dataIndex]
                };
            },
            setDataSource: function (dataSource) {
                this.options.dataSource = dataSource;
                this._dataSource();
                if (this.measuresTarget) {
                    this.measuresTarget.setDataSource(dataSource);
                }
                if (this.rowsTarget) {
                    this.rowsTarget.setDataSource(dataSource);
                }
                if (this.columnsTarget) {
                    this.columnsTarget.setDataSource(dataSource);
                }
                this._bindConfigurator();
                if (this.options.autoBind) {
                    dataSource.fetch();
                }
            },
            setOptions: function (options) {
                Widget.fn.setOptions.call(this, options);
                this._templates();
            },
            destroy: function () {
                Widget.fn.destroy.call(this);
                clearTimeout(this._headerReflowTimeout);
            },
            _dataSource: function () {
                var that = this;
                var dataSource = that.options.dataSource;
                dataSource = $.isArray(dataSource) ? { data: dataSource } : dataSource;
                if (that.dataSource && this._refreshHandler) {
                    that.dataSource.unbind(CHANGE, that._refreshHandler).unbind(STATERESET, that._stateResetHandler).unbind(PROGRESS, that._progressHandler).unbind(ERROR, that._errorHandler);
                } else {
                    that._refreshHandler = $.proxy(that.refresh, that);
                    that._progressHandler = $.proxy(that._requestStart, that);
                    that._stateResetHandler = $.proxy(that._stateReset, that);
                    that._errorHandler = $.proxy(that._error, that);
                }
                that.dataSource = kendo.data.PivotDataSource.create(dataSource).bind(CHANGE, that._refreshHandler).bind(PROGRESS, that._progressHandler).bind(STATERESET, that._stateResetHandler).bind(ERROR, that._errorHandler);
            },
            _error: function () {
                this._progress(false);
            },
            _requestStart: function () {
                this._progress(true);
            },
            _stateReset: function () {
                this._columnBuilder.reset();
                this._rowBuilder.reset();
            },
            _wrapper: function () {
                var height = this.options.height;
                this.wrapper = this.element.addClass('k-widget k-pivot');
                if (height) {
                    this.wrapper.css('height', height);
                }
            },
            _measureFields: function () {
                this.measureFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-measures');
                this.measuresTarget = this._createSettingTarget(this.measureFields, {
                    setting: 'measures',
                    messages: { empty: this.options.messages.measureFields }
                });
            },
            _createSettingTarget: function (element, options) {
                var template = '<span tabindex="0" class="k-button" data-' + kendo.ns + 'name="${data.name}">${data.name}';
                var sortable = options.sortable;
                var icons = '';
                if (sortable) {
                    icons += '#if (data.sortIcon) {#';
                    icons += '<span class="k-icon ${data.sortIcon}-sm"></span>';
                    icons += '#}#';
                }
                if (options.filterable || sortable) {
                    icons += '<span class="k-icon k-i-more-vertical k-setting-fieldmenu"></span>';
                }
                if (this.options.reorderable) {
                    icons += '<span class="k-icon k-i-close k-setting-delete"></span>';
                }
                if (icons) {
                    template += '<span class="k-field-actions">' + icons + '</span>';
                }
                template += '</span>';
                return new kendo.ui.PivotSettingTarget(element, $.extend({
                    template: template,
                    emptyTemplate: '<span class="k-empty">${data}</span>',
                    enabled: this.options.reorderable,
                    dataSource: this.dataSource
                }, options));
            },
            _initSettingTargets: function () {
                this.columnsTarget = this._createSettingTarget(this.columnFields, {
                    connectWith: this.rowFields,
                    setting: 'columns',
                    filterable: this.options.filterable,
                    sortable: this.options.sortable,
                    messages: {
                        empty: this.options.messages.columnFields,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
                this.rowsTarget = this._createSettingTarget(this.rowFields, {
                    connectWith: this.columnFields,
                    setting: 'rows',
                    filterable: this.options.filterable,
                    sortable: this.options.sortable,
                    messages: {
                        empty: this.options.messages.rowFields,
                        fieldMenu: this.options.messages.fieldMenu
                    }
                });
            },
            _createLayout: function () {
                var that = this;
                var layoutTable = $(LAYOUT_TABLE);
                var leftContainer = layoutTable.find('.k-pivot-rowheaders');
                var rightContainer = layoutTable.find('.k-pivot-table');
                var gridWrapper = $(DIV).addClass('k-grid k-widget');
                that._measureFields();
                that.columnFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-columns');
                that.rowFields = $(DIV).addClass('k-pivot-toolbar k-header k-settings-rows');
                that.columnsHeader = $('<div class="k-grid-header-wrap" />').wrap('<div class="k-grid-header" />');
                that.columnsHeader.parent().css('padding-right', kendo.support.scrollbar());
                that.rowsHeader = $('<div class="k-grid k-widget k-alt"/>');
                that.content = $('<div class="k-grid-content" />');
                leftContainer.append(that.measureFields);
                leftContainer.append(that.rowFields);
                leftContainer.append(that.rowsHeader);
                gridWrapper.append(that.columnsHeader.parent());
                gridWrapper.append(that.content);
                rightContainer.append(that.columnFields);
                rightContainer.append(gridWrapper);
                that.wrapper.append(layoutTable);
                that.columnsHeaderTree = new kendo.dom.Tree(that.columnsHeader[0]);
                that.rowsHeaderTree = new kendo.dom.Tree(that.rowsHeader[0]);
                that.contentTree = new kendo.dom.Tree(that.content[0]);
                that._initSettingTargets();
            },
            _progress: function (toggle) {
                kendo.ui.progress(this.wrapper, toggle);
            },
            _resize: function () {
                if (this.content[0].firstChild) {
                    this._setSectionsWidth();
                    this._setSectionsHeight();
                    this._setContentWidth();
                    this._setContentHeight();
                    this._columnHeaderReflow();
                }
            },
            _columnHeaderReflow: function () {
                var columnTable = this.columnsHeader.children('table');
                if (!kendo.support.browser.mozilla) {
                    return;
                }
                clearTimeout(this._headerReflowTimeout);
                columnTable.css('table-layout', 'auto');
                this._headerReflowTimeout = setTimeout(function () {
                    columnTable.css('table-layout', '');
                });
            },
            _setSectionsWidth: function () {
                var rowsHeader = this.rowsHeader;
                var leftColumn = rowsHeader.parent('.k-pivot-rowheaders').width(AUTO);
                var width;
                width = Math.max(outerWidth(this.measureFields), outerWidth(this.rowFields));
                width = Math.max(rowsHeader.children('table').width(), width);
                leftColumn.width(width);
            },
            _setSectionsHeight: function () {
                var measureFieldsHeight = this.measureFields.height(AUTO).height();
                var columnFieldsHeight = this.columnFields.height(AUTO).height();
                var rowFieldsHeight = this.rowFields.height(AUTO).innerHeight();
                var columnsHeight = this.columnsHeader.height(AUTO).innerHeight();
                var padding = rowFieldsHeight - this.rowFields.height();
                var firstRowHeight = columnFieldsHeight > measureFieldsHeight ? columnFieldsHeight : measureFieldsHeight;
                var secondRowHeight = columnsHeight > rowFieldsHeight ? columnsHeight : rowFieldsHeight;
                this.measureFields.height(firstRowHeight);
                this.columnFields.height(firstRowHeight);
                this.rowFields.height(secondRowHeight - padding);
                this.columnsHeader.height(secondRowHeight);
            },
            _setContentWidth: function () {
                var contentTable = this.content.find('table');
                var columnTable = this.columnsHeader.children('table');
                var rowLength = contentTable.children('colgroup').children().length;
                var calculatedWidth = rowLength * this.options.columnWidth;
                var minWidth = Math.ceil(calculatedWidth / this.content.width() * 100);
                if (minWidth < 100) {
                    minWidth = 100;
                }
                contentTable.add(columnTable).css('width', minWidth + '%');
                this._resetColspan(columnTable);
            },
            _setContentHeight: function () {
                var that = this;
                var content = that.content;
                var rowsHeader = that.rowsHeader;
                var innerHeight = that.wrapper.innerHeight();
                var scrollbar = kendo.support.scrollbar();
                var skipScrollbar = content[0].offsetHeight === content[0].clientHeight;
                var height = that.options.height;
                if (that.wrapper.is(':visible')) {
                    if (!innerHeight || !height) {
                        if (skipScrollbar) {
                            scrollbar = 0;
                        }
                        content.height('auto');
                        rowsHeader.height(content.height() - scrollbar);
                        return;
                    }
                    innerHeight -= outerHeight(that.columnFields);
                    innerHeight -= outerHeight(that.columnsHeader);
                    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) {
                    var min = options.min;
                    var max = options.max;
                    var today = new DATE();
                    if (getMilliseconds(min) == getMilliseconds(max)) {
                        min = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 0, 0, 0);
                        max = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), 24, 0, 0);
                    } else {
                        min = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), min.getHours(), min.getMinutes(), min.getSeconds(), min.getMilliseconds());
                        max = new DATE(today.getFullYear(), today.getMonth(), today.getDate(), max.getHours(), max.getMinutes(), max.getSeconds(), max.getMilliseconds());
                    }
                    that._dateInput = new ui.DateInput(element, {
                        culture: options.culture,
                        format: options.format,
                        min: min,
                        max: max,
                        value: options.value
                    });
                }
                that._old = that._update(options.value || that.element.val());
                that._oldText = element.val();
                kendo.notify(that);
            },
            options: {
                name: 'TimePicker',
                min: TODAY,
                max: TODAY,
                format: '',
                dates: [],
                parseFormats: [],
                value: null,
                interval: 30,
                height: 200,
                animation: {}
            },
            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 (e) {
                    e.preventDefault();
                    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 = kendoHtmlElement(column.text);
                        headers.push(kendoDomElement('th', {
                            colspan: column.span,
                            className: styles.header + (column.isNonWorking ? ' ' + styles.nonWorking : '')
                        }, [headerText]));
                    }
                    rows.push(kendoDomElement('tr', null, headers));
                }
                return rows;
            },
            _hours: function (start, end) {
                var slotEnd;
                var slots = [];
                var options = this.options;
                var workDayStart = options.workDayStart.getHours();
                var workDayEnd = options.workDayEnd.getHours();
                var isWorkHour;
                var hours;
                var hourSpan = options.hourSpan;
                start = new Date(start);
                end = new Date(end);
                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 (column.attributes) {
                    extend(true, attr, column.attributes);
                }
                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.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 (sheet) {
                var x = this._canInsertRef();
                if (x) {
                    var ref = sheet.selection()._ref.simplify().clone().relative(0, 0, 3);
                    if (sheet !== this.activeSheet) {
                        ref = ref.setSheet(sheet.name(), true);
                    }
                    this._replaceAt(x, ref.print(0, 0));
                }
            },
            _replaceAt: function (ctx, newValue) {
                var value = this.value();
                var tok = ctx.token;
                var rest = value.substr(ctx.end);
                value = value.substr(0, ctx.replace ? tok.begin : ctx.end) + newValue;
                var point = value.length;
                value += rest;
                this._value(value);
                this.setPos(point);
                this.scale();
                this._syntaxHighlight();
                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);
                    if (!this.formats.value(start, end)) {
                        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,
                    ref: this._ref
                });
            },
            _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.clone(exp.sheet, exp.row, exp.col);
        return formula;
        function js(node) {
            var type = node.type;
            if (type == 'num') {
                return node.value + '';
            } else if (type == 'str') {
                return JSON.stringify(node.value);
            } else if (type == 'error') {
                return 'context.error(' + JSON.stringify(node.value) + ')';
            } else if (type == 'return') {
                return 'context.resolve(' + js(node.value) + ')';
            } else if (type == 'func') {
                return 'context.func(' + JSON.stringify(node.func) + ', ' + js(node.args[0]) + ', ' + jsArray(node.args.slice(1)) + ')';
            } else if (type == 'call') {
                return js(node.func) + '(' + node.args.map(js).join(', ') + ')';
            } else if (type == 'ref') {
                return 'refs[' + node.index + ']';
            } else if (type == 'bool') {
                return '' + node.value;
            } else if (type == 'if') {
                return '(context.bool(' + js(node.co) + ') ? ' + js(node.th) + ' : ' + js(node.el) + ')';
            } else if (type == 'lambda') {
                return '(function(' + node.vars.join(', ') + '){ return(' + js(node.body) + ') })';
            } else if (type == 'var') {
                return node.name;
            } else if (type == 'matrix') {
                return jsArray(node.value);
            } else if (type == 'null') {
                return 'null';
            } else {
                throw new Error('Cannot compile expression ' + type);
            }
        }
        function jsArray(a) {
            return '[ ' + a.map(js).join(', ') + ' ]';
        }
    }
    function identity(x) {
        return x;
    }
    function TokenStream(input, options) {
        input = RawTokenStream(InputStream(input), options);
        var ahead = input.ahead;
        var skip = input.skip;
        var token = null;
        var fixCell = options.row != null && options.col != null ? function (cell) {
            if (cell.rel & 1) {
                cell.col -= options.col;
            }
            if (cell.rel & 2) {
                cell.row -= options.row;
            }
            return cell;
        } : identity;
        var addPos = options.forEditor ? function (thing, startToken, endToken) {
            thing.begin = startToken.begin;
            thing.end = endToken.end;
            return thing;
        } : identity;
        return {
            peek: peek,
            next: next,
            croak: input.croak,
            eof: input.eof,
            is: is
        };
        function is(type, value) {
            var tok = peek();
            return tok != null && (type == null || tok.type === type) && (value == null || tok.value === value) ? tok : null;
        }
        function peek() {
            if (token == null) {
                token = readNext();
            }
            return token;
        }
        function next() {
            if (token != null) {
                var tmp = token;
                token = null;
                return tmp;
            }
            return readNext();
        }
        function readNext() {
            var ret;
            var t = input.peek();
            if (t) {
                if (t.type == 'sym' || t.type == 'rc' || t.type == 'num') {
                    ret = ahead(8, refRange3D) || ahead(6, refCell3D) || ahead(6, refSheetRange) || ahead(4, refSheetCell) || ahead(4, refRange) || ahead(2, refCell) || ahead(2, funcall);
                }
                if (!ret) {
                    ret = input.next();
                }
            }
            return ret;
        }
        function toCell(tok, isFirst) {
            if (tok.type == 'rc') {
                if (tok.rel && !options.forEditor && (options.row == null || options.col == null)) {
                    input.croak('Cannot read relative cell in RC notation');
                }
                return new CellRef(tok.row, tok.col, tok.rel);
            }
            if (tok.type == 'num') {
                if (tok.value <= 1048577) {
                    return fixCell(new CellRef(getrow(tok.value), isFirst ? -Infinity : +Infinity, 2));
                } else {
                    return null;
                }
            }
            var name = tok.value;
            var m = /^(\$)?([a-z]+)(\$)?(\d+)$/i.exec(name);
            if (m) {
                var row = getrow(m[4]), col = getcol(m[2]);
                if (row <= 1048576 && col <= 16383) {
                    return fixCell(new CellRef(getrow(m[4]), getcol(m[2]), (m[1] ? 0 : 1) | (m[3] ? 0 : 2)));
                } else {
                    return null;
                }
            }
            var abs = name.charAt(0) == '$';
            if (abs) {
                name = name.substr(1);
            }
            if (/^\d+$/.test(name)) {
                var row = getrow(name);
                if (row <= 1048576) {
                    return fixCell(new CellRef(getrow(name), isFirst ? -Infinity : +Infinity, abs ? 0 : 2));
                }
            } else {
                var col = getcol(name);
                if (col <= 16383) {
                    return fixCell(new CellRef(isFirst ? -Infinity : +Infinity, getcol(name), abs ? 0 : 1));
                }
            }
        }
        function refRange3D(a, b, c, d, e, f, g, h) {
            if (a.type == 'sym' && b.type == 'op' && b.value == ':' && c.type == 'sym' && d.type == 'punc' && d.value == '!' && (e.type == 'sym' || e.type == 'rc' || e.type == 'num' && e.value == e.value | 0) && f.type == 'op' && f.value == ':' && (g.type == 'sym' || g.type == 'rc' || g.type == 'num' && g.value == g.value | 0) && g.type == e.type && !(h.type == 'punc' && h.value == '(' && !g.space)) {
                var tl = toCell(e, true), br = toCell(g, false);
                if (tl && br) {
                    skip(7);
                    return addPos(new RangeRef(tl.setSheet(a.value, true), br.setSheet(c.value, true)).setSheet(a.value, true), a, g);
                }
            }
        }
        function refCell3D(a, b, c, d, e, f) {
            if (a.type == 'sym' && b.type == 'op' && b.value == ':' && c.type == 'sym' && d.type == 'punc' && d.value == '!' && (e.type == 'sym' || e.type == 'rc' || e.type == 'num' && e.value == e.value | 0) && !(f.type == 'punc' && f.value == '(' && !e.space)) {
                var tl = toCell(e);
                if (tl) {
                    skip(5);
                    var br = tl.clone();
                    return addPos(new RangeRef(tl.setSheet(a.value, true), br.setSheet(c.value, true)).setSheet(a.value, true), a, e);
                }
            }
        }
        function refSheetRange(a, b, c, d, e, f) {
            if (a.type == 'sym' && b.type == 'punc' && b.value == '!' && (c.type == 'sym' || c.type == 'rc' || c.type == 'num' && c.value == c.value | 0) && d.type == 'op' && d.value == ':' && (e.type == 'sym' || e.type == 'rc' || e.type == 'num' && e.value == e.value | 0) && !(f.type == 'punc' && f.value == '(' && !e.space)) {
                var tl = toCell(c, true), br = toCell(e, false);
                if (tl && br) {
                    skip(5);
                    return addPos(new RangeRef(tl, br).setSheet(a.value, true), a, e);
                }
            }
        }
        function refSheetCell(a, b, c, d) {
            if (a.type == 'sym' && b.type == 'punc' && b.value == '!' && (c.type == 'sym' || c.type == 'rc' || c.type == 'num' && c.value == c.value | 0) && !(d.type == 'punc' && d.value == '(' && !c.space)) {
                skip(3);
                var x = toCell(c);
                if (!x || !isFinite(x.row)) {
                    x = new NameRef(c.value);
                }
                return addPos(x.setSheet(a.value, true), a, c);
            }
        }
        function refRange(a, b, c, d) {
            if ((a.type == 'sym' || a.type == 'rc' || a.type == 'num' && a.value == a.value | 0) && (b.type == 'op' && b.value == ':') && (c.type == 'sym' || c.type == 'rc' || c.type == 'num' && c.value == c.value | 0) && !(d.type == 'punc' && d.value == '(' && !c.space)) {
                var tl = toCell(a, true), br = toCell(c, false);
                if (tl && br) {
                    skip(3);
                    return addPos(new RangeRef(tl, br), a, c);
                }
            }
        }
        function refCell(a, b) {
            if ((a.type == 'sym' || a.type == 'rc') && !(b.type == 'punc' && b.value == '(' && !a.space)) {
                var x = toCell(a);
                if (x && isFinite(x.row) && isFinite(x.col)) {
                    skip(1);
                    return addPos(x, a, a);
                }
            }
        }
        function funcall(a, b) {
            if (a.type == 'sym' && b.type == 'punc' && b.value == '(' && !a.space) {
                a.type = 'func';
                skip(1);
                return a;
            }
        }
    }
    function isWhitespace(ch) {
        return ' \t\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);
                    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().selection(),
                    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) {
                var sheet = e.range._sheet;
                if (this._workbook.activeSheet() !== sheet) {
                    this._workbook.activeSheet()._setFormulaSelections();
                    this._workbook.activeSheet(sheet);
                }
                sheet.isInEditMode(false);
                this._lastEditorValue = e.value;
                this._execute({
                    command: 'EditCommand',
                    options: {
                        operatingRange: e.range,
                        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().selection(),
                    rect: this.view.activeCellRectangle(),
                    tooltip: this._activeTooltip()
                });
            },
            onEditorCellFocus: function () {
                this.editor.scale();
            },
            onEditorEsc: function () {
                this.resetEditorValue();
                this.editor.deactivate();
                this.clipboardElement.focus();
            },
            insertNewline: function (e) {
                e.preventDefault();
                this.editor.insertNewline();
            },
            onEditorBlur: function (_, action) {
                if (this.editor.isFiltered()) {
                    return;
                }
                this._preventNavigation = false;
                this.editor.deactivate();
                if (!this._preventNavigation) {
                    this.clipboardElement.focus();
                    this.navigator.navigateInSelection(ENTRY_ACTIONS[action]);
                }
            },
            onEditorAction: function (event, action) {
                var editor = this.editor;
                var sheet = this._workbook.activeSheet();
                if (editor.canInsertRef(true)) {
                    this.navigator.moveActiveCell(ACTIONS[action]);
                    editor.activeEditor().refAtPoint(sheet);
                    sheet._setFormulaSelections(editor.highlightedRefs());
                    event.preventDefault();
                }
            },
            onEditorShiftAction: function (event, action) {
                var editor = this.editor;
                var sheet = this._workbook.activeSheet();
                if (editor.canInsertRef(true)) {
                    this.navigator.modifySelection(ACTIONS[action.replace('shift+', '')], this.appendSelection);
                    editor.activeEditor().refAtPoint(sheet);
                    sheet._setFormulaSelections(editor.highlightedRefs());
                    event.preventDefault();
                }
            },
            resetEditorValue: function () {
                this.editor.value(this._workbook._inputForRef(this._workbook.activeSheet()._viewActiveCell()));
            },
            activateEditor: function () {
                this.editor.activate({
                    range: this._workbook.activeSheet().selection(),
                    rect: this.view.activeCellRectangle(),
                    tooltip: this._activeTooltip()
                }).focus();
            },
            deactivateEditor: function () {
                this.view.editor.deactivate();
            },
            onCommandRequest: function (e) {
                if (e.command) {
                    this._execute(e);
                } else {
                    this._workbook.undoRedoStack[e.action]();
                }
            },
            onDialogRequest: function (e) {
                var additionalOptions = {
                    pdfExport: this._workbook.options.pdf,
                    excelExport: this._workbook.options.excel
                };
                if (e.options) {
                    $.extend(true, e.options, additionalOptions);
                } else {
                    e.options = additionalOptions;
                }
                this.view.openDialog(e.name, e.options);
            },
            onNameEditorEnter: function () {
                var ref;
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                var name = this.view.nameEditor.value();
                ref = kendo.spreadsheet.calc.parseReference(name, true) || workbook.nameValue(name);
                if (ref instanceof kendo.spreadsheet.Ref) {
                    if (ref.sheet && ref.sheet.toLowerCase() != sheet.name().toLowerCase()) {
                        var tmp = workbook.sheetByName(ref.sheet);
                        if (tmp) {
                            workbook.activeSheet(tmp);
                            sheet = tmp;
                        }
                    }
                    sheet.range(ref).select();
                    return;
                }
                ref = sheet.selection()._ref.clone().simplify().setSheet(sheet.name(), true);
                this._execute({
                    command: 'DefineNameCommand',
                    options: {
                        name: name,
                        value: ref
                    }
                });
                this.clipboardElement.focus();
            },
            onNameEditorCancel: function () {
                this.clipboardElement.focus();
            },
            onNameEditorSelect: function (ev) {
                var name = ev.name;
                var workbook = this._workbook;
                var sheet = workbook.activeSheet();
                var ref = workbook.nameValue(name);
                if (ref instanceof kendo.spreadsheet.Ref) {
                    if (ref.sheet && ref.sheet.toLowerCase() != sheet.name().toLowerCase()) {
                        var tmp = workbook.sheetByName(ref.sheet);
                        if (tmp) {
                            workbook.activeSheet(tmp);
                            sheet = tmp;
                        }
                    }
                    sheet.range(ref).select();
                    return;
                }
                this.clipboardElement.focus();
            },
            onNameEditorDelete: function (ev) {
                this._execute({
                    command: 'DeleteNameCommand',
                    options: { name: ev.name }
                });
                this.clipboardElement.focus();
            }
        });
        kendo.spreadsheet.Controller = Controller;
    }(window.kendo));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('spreadsheet/view', [
        'kendo.core',
        'kendo.menu',
        'spreadsheet/sheetsbar'
    ], 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);
                    }
                }
                this.resize();
            },
            _tools: function () {
                return this.element.find('[data-property]').toArray().map(function (element) {
                    element = $(element);
                    return {
                        property: element.attr('data-property'),
                        tool: this._getItem(element)
                    };
                }.bind(this));
            },
            destroy: function () {
                this.element.find('[data-command],.k-button').each(function () {
                    var element = $(this);
                    var instance = element.data('instance');
                    if (instance && instance.destroy) {
                        instance.destroy();
                    }
                });
                ToolBar.fn.destroy.call(this);
            }
        });
        kendo.spreadsheet.ToolBar = SpreadsheetToolBar;
        var DropDownTool = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                var dropDownList = $('<select />').attr('title', options.attributes.title).attr('aria-label', options.attributes.title).kendoDropDownList({ height: 'auto' }).data('kendoDropDownList');
                this.dropDownList = dropDownList;
                this.element = dropDownList.wrapper;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                dropDownList.bind('open', this._open.bind(this));
                dropDownList.bind('change', this._change.bind(this));
                this.element.width(options.width).attr({
                    'data-command': 'PropertyChangeCommand',
                    'data-property': options.property
                });
            },
            _open: function () {
                var ddl = this.dropDownList;
                var list = ddl.list;
                var listWidth;
                list.css({
                    whiteSpace: 'nowrap',
                    width: 'auto'
                });
                listWidth = list.width();
                if (listWidth) {
                    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-download\' />' + '</button>').attr('title', this._title).attr('aria-label', this._title).data('instance', this);
                this.element.bind('click', this.open.bind(this)).data('instance', this);
            },
            open: function () {
                this.toolbar.dialog({ name: this._dialogName });
            }
        }));
        var OverflowDialogButton = kendo.toolbar.OverflowButton.extend({
            init: function (options, toolbar) {
                kendo.toolbar.OverflowButton.fn.init.call(this, options, toolbar);
                this.element.on('click touchend', this._click.bind(this));
                this.message = this.options.text;
                var instance = this.element.data('button');
                this.element.data(this.options.type, instance);
            },
            _click: $.noop
        });
        var ColorPicker = PopupTool.extend({
            init: function (options, toolbar) {
                PopupTool.fn.init.call(this, options, toolbar);
                this.popup.element.addClass('k-spreadsheet-colorpicker');
                this.colorChooser = new kendo.spreadsheet.ColorChooser(this.popup.element, { change: this._colorChange.bind(this) });
                this.element.attr({ 'data-property': options.property });
                this.element.data({
                    type: 'colorPicker',
                    colorPicker: this,
                    instance: this
                });
            },
            destroy: function () {
                this.colorChooser.destroy();
                PopupTool.fn.destroy.call(this);
            },
            update: function (value) {
                this.value(value);
            },
            value: function (value) {
                this.colorChooser.value(value);
            },
            _colorChange: function (e) {
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.options.property,
                        value: e.sender.value()
                    }
                });
                this.popup.close();
            }
        });
        var ColorPickerButton = OverflowDialogButton.extend({
            init: function (options, toolbar) {
                options.iconName = 'text';
                OverflowDialogButton.fn.init.call(this, options, toolbar);
            },
            _click: function () {
                this.toolbar.dialog({
                    name: 'colorPicker',
                    options: {
                        title: this.options.property,
                        property: this.options.property
                    }
                });
            }
        });
        kendo.toolbar.registerComponent('colorPicker', ColorPicker, ColorPickerButton);
        var FONT_SIZES = [
            8,
            9,
            10,
            11,
            12,
            13,
            14,
            16,
            18,
            20,
            22,
            24,
            26,
            28,
            36,
            48,
            72
        ];
        var DEFAULT_FONT_SIZE = 12;
        var FontSize = kendo.toolbar.Item.extend({
            init: function (options, toolbar) {
                var comboBox = $('<input />').attr('aria-label', options.attributes.title).kendoComboBox({
                    change: this._valueChange.bind(this),
                    clearButton: false,
                    dataSource: options.fontSizes || FONT_SIZES,
                    value: DEFAULT_FONT_SIZE
                }).data('kendoComboBox');
                this.comboBox = comboBox;
                this.element = comboBox.wrapper;
                this.options = options;
                this.toolbar = toolbar;
                this.attributes();
                this.addUidAttr();
                this.addOverflowAttr();
                this.element.width(options.width).attr({
                    'data-command': 'PropertyChangeCommand',
                    'data-property': options.property
                });
                this.element.data({
                    type: 'fontSize',
                    fontSize: this
                });
            },
            _valueChange: function (e) {
                this.toolbar.action({
                    command: 'PropertyChangeCommand',
                    options: {
                        property: this.options.property,
                        value: kendo.parseInt(e.sender.value())
                    }
                });
            },
            update: function (value) {
                this.value(kendo.parseInt(value) || DEFAULT_FONT_SIZE);
            },
            value: function (value) {
                if (value !== undefined) {
                    this.comboBox.value(value);
                } else {
                    return this.comboBox.value();
                }
            }
        });
        var FontSizeButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({
                    name: 'fontSize',
                    options: {
                        sizes: FONT_SIZES,
                        defaultSize: DEFAULT_FONT_SIZE
                    }
                });
            },
            update: function (value) {
                this._value = value || DEFAULT_FONT_SIZE;
                this.element.find('.k-text').text(this.message + ' (' + this._value + ') ...');
            }
        });
        kendo.toolbar.registerComponent('fontSize', FontSize, FontSizeButton);
        var FONT_FAMILIES = [
            'Arial',
            'Courier New',
            'Georgia',
            'Times New Roman',
            'Trebuchet MS',
            'Verdana'
        ];
        var DEFAULT_FONT_FAMILY = 'Arial';
        var FontFamily = DropDownTool.extend({
            init: function (options, toolbar) {
                DropDownTool.fn.init.call(this, options, toolbar);
                var ddl = this.dropDownList;
                ddl.setDataSource(options.fontFamilies || FONT_FAMILIES);
                ddl.value(DEFAULT_FONT_FAMILY);
                this.element.data({
                    type: 'fontFamily',
                    fontFamily: this
                });
            },
            update: function (value) {
                this.value(value || DEFAULT_FONT_FAMILY);
            }
        });
        var FontFamilyButton = OverflowDialogButton.extend({
            _click: function () {
                this.toolbar.dialog({
                    name: 'fontFamily',
                    options: {
                        fonts: FONT_FAMILIES,
                        defaultFont: DEFAULT_FONT_FAMILY
                    }
                });
            },
            update: function (value) {
                this._value = value || DEFAULT_FONT_FAMILY;
                this.element.find('.k-text').text(this.message + ' (' + this._value + ') ...');
            }
        });
        kendo.toolbar.registerComponent('fontFamily', FontFamily, FontFamilyButton);
        var defaultFormats = kendo.spreadsheet.formats = {
            automatic: null,
            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" ' + 'title="#: messages.validationDialog.labels.criteria #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: criterion, source: criteria" />' + '</div>' + '<div data-bind="visible: isNumber">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.comparer #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + 'title="#: messages.validationDialog.labels.comparer #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: comparer, source: comparers" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.min #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.min #" title="#: messages.validationDialog.labels.min #" placeholder="e.g. 10" class="k-textbox" data-bind="value: from, enabled: isNumber" required="required" />' + '</div>' + '<div data-bind="visible: showTo">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.max #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.max #" title="#: messages.validationDialog.labels.max #" placeholder="e.g. 100" class="k-textbox" data-bind="value: to, enabled: showToForNumber" required="required" />' + '</div>' + '</div>' + '</div>' + '<div data-bind="visible: isText">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.comparer #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + 'title="#: messages.validationDialog.labels.comparer #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: comparer, source: comparers" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.value #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.value #" title="#: messages.validationDialog.labels.value #" class="k-textbox" data-bind="value: from, enabled: isText" required="required" />' + '</div>' + '</div>' + '<div data-bind="visible: isDate">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.comparer #:</label></div>' + '<div class="k-edit-field">' + '<select data-role="dropdownlist" ' + 'title="#: messages.validationDialog.labels.comparer #"' + 'data-text-field="name" ' + 'data-value-field="type" ' + 'data-bind="value: comparer, source: comparers" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.start #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.start #" title="#: messages.validationDialog.labels.start #" class="k-textbox" data-bind="value: from, enabled: isDate" required="required" />' + '</div>' + '<div data-bind="visible: showTo">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.end #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.end #" title="#: messages.validationDialog.labels.end #" class="k-textbox" data-bind="value: to, enabled: showToForDate" required="required" />' + '</div>' + '</div>' + '</div>' + '<div data-bind="visible: isCustom">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.value #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.value #" title="#: messages.validationDialog.labels.value #" class="k-textbox" data-bind="value: from, enabled: isCustom" required="required" />' + '</div>' + '</div>' + '<div data-bind="visible: isList">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.value #:</label></div>' + '<div class="k-edit-field">' + '<input name="#: messages.validationDialog.labels.value #" title="#: messages.validationDialog.labels.value #" class="k-textbox" data-bind="value: from, enabled: isList" required="required" />' + '</div>' + '</div>' + '<div data-bind="visible: isList">' + '<div class="k-edit-field">' + '<input type="checkbox" name="showButton" id="listShowButton" class="k-checkbox" data-bind="checked: showButton"/>' + '<label for="listShowButton" class="k-checkbox-label">' + ' #: messages.validationDialog.labels.showListButton #' + '</label>' + '</div>' + '</div>' + '<div data-bind="visible: isDate">' + '<div class="k-edit-field">' + '<input type="checkbox" name="showButton" id="dateShowButton" class="k-checkbox" data-bind="checked: showButton"/>' + '<label for="dateShowButton" class="k-checkbox-label">' + ' #: messages.validationDialog.labels.showCalendarButton #' + '</label>' + '</div>' + '</div>' + '<div data-bind="invisible: isAny">' + '<div class="k-edit-field">' + '<input type="checkbox" title="#: messages.validationDialog.labels.ignoreBlank #" name="ignoreBlank" id="ignoreBlank" class="k-checkbox" data-bind="checked: ignoreBlank"/>' + '<label for="ignoreBlank" class="k-checkbox-label">' + ' #: messages.validationDialog.labels.ignoreBlank #' + '</label>' + '</div>' + '</div>' + '<div data-bind="invisible: isAny">' + '<div class="k-action-buttons"></div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.onInvalidData #:</label></div>' + '<div class="k-edit-field">' + '<input type="radio" title="#: messages.validationDialog.labels.rejectInput #" id="validationTypeReject" name="validationType" value="reject" data-bind="checked: type" class="k-radio" />' + '<label for="validationTypeReject" class="k-radio-label">' + '#: messages.validationDialog.labels.rejectInput #' + '</label> ' + '<input type="radio" title="#: messages.validationDialog.labels.showWarning #" id="validationTypeWarning"  name="validationType" value="warning" data-bind="checked: type" class="k-radio" />' + '<label for="validationTypeWarning" class="k-radio-label">' + '#: messages.validationDialog.labels.showWarning #' + '</label>' + '</div>' + '</div>' + '<div data-bind="invisible: isAny" class="hint-wrapper">' + '<div class="k-edit-field">' + '<input type="checkbox" title="#: messages.validationDialog.labels.showHint #" name="useCustomMessages" id="useCustomMessages" class="k-checkbox" data-bind="checked: useCustomMessages" />' + '<label class="k-checkbox-label" for="useCustomMessages">' + ' #: messages.validationDialog.labels.showHint #' + '</label>' + '</div>' + '<div data-bind="visible: useCustomMessages">' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.hintTitle #:</label></div>' + '<div class="k-edit-field">' + '<input class="k-textbox" title="#: messages.validationDialog.labels.hintTitle #" placeholder="#: messages.validationDialog.placeholders.typeTitle #" data-bind="value: hintTitle" />' + '</div>' + '<div class="k-edit-label"><label>#: messages.validationDialog.labels.hintMessage #:</label></div>' + '<div class="k-edit-field">' + '<input class="k-textbox" title="#: messages.validationDialog.labels.hintMessage #" placeholder="#: messages.validationDialog.placeholders.typeMessage #" data-bind="value: hintMessage" />' + '</div>' + '</div>' + '</div>' + '<div class="k-action-buttons">' + '<button class="k-button" data-bind="visible: showRemove, click: remove">#: messages.remove #</button>' + '<button class="k-button k-primary" data-bind="click: apply">#: messages.apply #</button>' + '<button class="k-button" data-bind="click: close">#: messages.cancel #</button>' + '</div>' + '</div>'
            },
            open: function (range) {
                var options = this.options;
                var element;
                this.viewModel = new ValidationViewModel({
                    type: options.type,
                    defaultHintMessage: options.hintMessage,
                    defaultHintTitle: options.hintTitle,
                    defaultComparers: options.comparers.slice(0),
                    comparerMessages: options.comparerMessages,
                    criteria: options.criteria.slice(0),
                    criterion: options.criterion,
                    ignoreBlank: options.ignoreBlank,
                    showButton: options.showButton,
                    apply: this.apply.bind(this),
                    close: this.close.bind(this),
                    remove: this.remove.bind(this)
                });
                this.viewModel.update(range.validation());
                SpreadsheetDialog.fn.open.call(this);
                element = this.dialog().element;
                if (this.validatable) {
                    this.validatable.destroy();
                }
                kendo.bind(element, this.viewModel);
                this.validatable = new kendo.ui.Validator(element.find('.k-edit-form-container'), {
                    validateOnBlur: false,
                    errorTemplate: this.options.errorTemplate || undefined
                });
            },
            apply: function () {
                if (this.validatable.validate()) {
                    SpreadsheetDialog.fn.apply.call(this);
                    this.trigger('action', {
                        command: 'EditValidationCommand',
                        options: { value: this.viewModel.toValidationObject() }
                    });
                }
            },
            remove: function () {
                this.viewModel.set('criterion', 'any');
                this.apply();
            }
        });
        kendo.spreadsheet.dialogs.register('validation', ValidationDialog);
        kendo.spreadsheet.dialogs.ValidationDialog = ValidationDialog;
        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\' title=\'#: messages.linkDialog.labels.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();
            var valuesFilter = this;
            var values = this.values;
            for (var i = 0; i < data.length; i++) {
                var item = data[i];
                var text = item.text.toString().toLowerCase();
                var itemVisible = query === true || query === '' || text.indexOf(query) >= 0;
                var filterSpread = filter.bind(valuesFilter);
                var anyVisibleChildren = filterSpread(item.children, query);
                hasVisibleChildren = hasVisibleChildren || anyVisibleChildren || itemVisible;
                item.hidden = !itemVisible && !anyVisibleChildren;
                if (query.length || values && !values.length) {
                    item.checked = !item.hidden;
                } else if (values && values.indexOf(item.text) != -1) {
                    item.checked = true;
                }
            }
            if (data) {
                dataSource.filter({
                    field: 'hidden',
                    operator: 'neq',
                    value: true
                });
            }
            return hasVisibleChildren;
        }
        function uncheckAll(dataSource) {
            var data = dataSource instanceof kendo.data.HierarchicalDataSource && dataSource.data();
            for (var i = 0; i < data.length; i++) {
                var item = data[i];
                item.checked = false;
                if (item.hasChildren) {
                    uncheckAll(item.children);
                }
            }
        }
        var FilterMenuViewModel = kendo.spreadsheet.FilterMenuViewModel = kendo.data.ObservableObject.extend({
            valuesChange: function (e) {
                var dataSource = e ? e.sender.dataSource : this.valuesDataSource;
                var checked = function (item) {
                    return item.checked;
                };
                var value = function (item) {
                    return item.dataType === 'date' ? kendo.spreadsheet.dateToNumber(item.value) : item.value;
                };
                var unique = function (value, index, array) {
                    return array.lastIndexOf(value) === index;
                };
                var data = dataSource.data();
                var values = data[0].children.data().toJSON();
                var blanks = values.filter(function (item) {
                    return item.dataType === 'blank';
                });
                blanks = blanks.length ? blanks[0].checked : false;
                values = values.filter(checked).map(value);
                if (this.appendToSearch && this.valueFilter && this.valueFilter.values.length) {
                    values = values.concat(this.valueFilter.values.toJSON()).sort().filter(unique);
                }
                this.set('valueFilter', {
                    values: values,
                    blanks: blanks
                });
            },
            valueSelect: function (e) {
                e.preventDefault();
                var node = e.sender.dataItem(e.node);
                node.set('checked', !node.checked);
            },
            hasActiveSearch: false,
            appendToSearch: false,
            filterValues: function (e) {
                var query = typeof e == 'string' ? e : $(e.target).val().toLowerCase();
                var dataSource = this.valuesDataSource;
                this.set('hasActiveSearch', !!query);
                var filterSpread = filter.bind(this.valueFilter);
                uncheckAll(dataSource);
                filterSpread(dataSource, query);
            },
            reset: function () {
                this.set('customFilter', {
                    logic: 'and',
                    criteria: [{
                            operator: null,
                            value: null
                        }]
                });
                this.set('valueFilter', { values: [] });
            },
            operatorChange: function (e) {
                var dataItem = e.sender.dataItem();
                this.set('operatorType', dataItem.type);
                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: false,
                        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) {
                    var checked = true;
                    if (sheet.isHiddenRow(row)) {
                        checked = false;
                    }
                    var value = cell.value;
                    var dataType = cell.dataType;
                    var text = cell.text;
                    if (value === undefined) {
                        dataType = 'blank';
                    } else if (cell.format) {
                        dataType = kendo.spreadsheet.formatting.type(value, cell.format);
                    } else {
                        dataType = typeof value;
                    }
                    if (value !== null && cell.format) {
                        text = kendo.spreadsheet.formatting.text(value, cell.format);
                    } else {
                        text = dataType == 'blank' ? messages.blanks : value;
                    }
                    if (dataType === 'percent') {
                        dataType = 'number';
                    }
                    if (dataType === 'date') {
                        value = kendo.spreadsheet.numberToDate(value);
                    }
                    values.push({
                        dataType: dataType,
                        value: value,
                        text: text,
                        checked: checked
                    });
                });
                values = distinctValues(values);
                values.sort(function (a, b) {
                    if (a.dataType === b.dataType) {
                        return 0;
                    }
                    if (a.dataType === 'blank' || b.dataType === 'blank') {
                        return a.dataType === 'blank' ? -1 : 1;
                    }
                    if (a.dataType === 'number' || b.dataType === 'number') {
                        return a.dataType === 'number' ? -1 : 1;
                    }
                    if (a.dataType === 'date' || b.dataType === 'date') {
                        return a.dataType === 'date' ? -1 : 1;
                    }
                    return 0;
                });
                return values;
            },
            filterType: function (range, column) {
                var sheet = range.sheet();
                var filter = this.filterForColumn(column, sheet);
                var type;
                filter = filter && filter.filter.toJSON();
                if (filter && filter.filter == 'custom') {
                    var value = filter.criteria[0].value;
                    if (value instanceof Date) {
                        type = 'date';
                    } else if (typeof value == 'string') {
                        type = 'string';
                    } else if (typeof value == 'number') {
                        type = 'number';
                    }
                }
                if (!type) {
                    var topValue = this.values(range.row(1), column)[0];
                    type = topValue && topValue.dataType;
                    if (type == 'blank') {
                        type = null;
                    }
                }
                return type;
            },
            filterForColumn: function (column, sheet) {
                var allFilters = sheet.filter();
                var filters;
                if (allFilters) {
                    filters = allFilters.columns.filter(function (item) {
                        return item.index === column;
                    })[0];
                }
                return filters;
            },
            filter: function (column, sheet) {
                var columnFilters = this.filterForColumn(column, sheet);
                if (!columnFilters) {
                    return;
                }
                var options = columnFilters.filter.toJSON();
                var type = options.filter;
                delete options.filter;
                var result = {
                    type: type,
                    options: options
                };
                var criteria = options.criteria;
                if (criteria && criteria.length) {
                    result.operator = criteria[0].operator;
                }
                return result;
            }
        };
        var FilterMenu = Widget.extend({
            init: function (element, options) {
                Widget.call(this, element, options);
                this.element.addClass(FilterMenu.classNames.wrapper);
                this.viewModel = new FilterMenuViewModel({
                    active: 'value',
                    operator: null,
                    operators: flattenOperators(this.options.operators),
                    clear: this.clear.bind(this),
                    apply: this.apply.bind(this)
                });
                this._filterInit();
                this._popup();
                this._sort();
                this._filterByCondition();
                this._filterByValue();
                this._actionButtons();
            },
            options: {
                name: 'FilterMenu',
                column: 0,
                range: null,
                operators: {
                    string: {
                        contains: 'Text contains',
                        doesnotcontain: 'Text does not contain',
                        startswith: 'Text starts with',
                        endswith: 'Text ends with',
                        matches: 'Text matches',
                        doesnotmatch: 'Text does not match'
                    },
                    date: {
                        eq: 'Date is',
                        neq: 'Date is not',
                        lt: 'Date is before',
                        gt: 'Date is after'
                    },
                    number: {
                        eq: 'Is equal to',
                        neq: 'Is not equal to',
                        gte: 'Is greater than or equal to',
                        gt: 'Is greater than',
                        lte: 'Is less than or equal to',
                        lt: 'Is less than'
                    }
                }
            },
            events: ['action'],
            destroy: function () {
                Widget.fn.destroy.call(this);
                this.menu.destroy();
                this.valuesTreeView.destroy();
                this.popup.destroy();
            },
            openFor: function (anchor) {
                this.popup.setOptions({ anchor: anchor });
                this.popup.open();
            },
            close: function () {
                this.popup.close();
            },
            clear: function () {
                this.action({
                    command: 'ClearFilterCommand',
                    options: { column: this.options.column }
                });
                this.viewModel.reset();
                this.close();
            },
            apply: function () {
                this._active();
                var options = {
                    operatingRange: this.options.range,
                    column: this.options.column
                };
                var valueFilter;
                var customFilter;
                if (this.viewModel.active === 'value') {
                    this.viewModel.valuesChange({ sender: this.valuesTreeView });
                    valueFilter = this.viewModel.valueFilter.toJSON();
                    if (valueFilter.blanks || valueFilter.values && valueFilter.values.length) {
                        options.valueFilter = valueFilter;
                    }
                } else if (this.viewModel.active === 'custom') {
                    customFilter = this.viewModel.customFilter.toJSON();
                    if (customFilter.criteria.length && customFilter.criteria[0].value !== null) {
                        options.customFilter = customFilter;
                    }
                }
                if (options.valueFilter || options.customFilter) {
                    this.action({
                        command: 'ApplyFilterCommand',
                        options: options
                    });
                }
            },
            action: function (options) {
                this.trigger('action', $.extend({}, options));
            },
            _filterInit: function () {
                var column = this.options.column;
                var range = this.options.range;
                var sheet = range.sheet();
                var activeFilter = FilterMenuController.filter(column, sheet);
                if (activeFilter) {
                    var filterType = FilterMenuController.filterType(range, column);
                    this.viewModel.set('active', activeFilter.type);
                    this.viewModel.set(activeFilter.type + 'Filter', activeFilter.options);
                    if (activeFilter.type == 'custom') {
                        this.viewModel.set('operator', filterType + '_' + activeFilter.operator);
                        this.viewModel.set('operatorType', filterType);
                    }
                } else {
                    this.viewModel.reset();
                }
            },
            _popup: function () {
                this.popup = this.element.kendoPopup({ copyAnchorStyles: false }).data('kendoPopup');
            },
            _sort: function () {
                var template = kendo.template(FilterMenu.templates.menuItem);
                var messages = 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._range = options.range;
                this.cellInput.position(options.rect);
                this.cellInput.resize(options.rect);
                this.cellInput.tooltip(options.tooltip);
                this.cellInput.activeCell = this.barInput.activeCell = this._range.topLeft();
                this.cellInput.activeSheet = this.barInput.activeSheet = this._range._sheet;
                this.trigger('activate');
                return this;
            },
            deactivate: function () {
                var cellInput = this.cellInput;
                if (!this._active) {
                    return;
                }
                if (cellInput.value() != this._value) {
                    this.trigger('change', {
                        value: cellInput.value(),
                        range: this._range
                    });
                }
                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 = Math.floor(options.pageWidth);
        var pageHeight = Math.floor(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.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 isFunction = kendo.isFunction;
        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 HIGHLIGHT_ZINDEX = 100;
        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,
            HIGHLIGHT_ZINDEX: HIGHLIGHT_ZINDEX
        };
        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;
        }
        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 (isString(formatString) && 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 (isString(formatString) && 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;
                this.rtl = context.rtl;
            },
            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
        };
        function getTemplate(options) {
            if (options === void 0) {
                options = {};
            }
            var template;
            if (options.template) {
                options.template = template = TemplateService.compile(options.template);
            } else if (isFunction(options.content)) {
                template = options.content;
            }
            return template;
        }
        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 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);
                    }
                    if (!defined(highlight.options.zIndex)) {
                        highlight.options.zIndex = valueOrDefault(options.zIndex, HIGHLIGHT_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 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) {
                        var noteTemplate = getTemplate(label);
                        if (noteTemplate) {
                            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 tmpl = getTemplate(options);
                var text = value;
                if (tmpl) {
                    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 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 MIN_CATEGORY_POINTS_RANGE = 0.01;
        function indexOf(value, arr) {
            if (value instanceof Date) {
                var length = arr.length;
                for (var idx = 0; idx < length; idx++) {
                    if (dateEquals(arr[idx], value)) {
                        return idx;
                    }
                }
                return -1;
            }
            return arr.indexOf(value);
        }
        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 = indexOf(value, options.srcCategories || options.categories);
                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 COORDINATE_LIMIT = 300000;
        var DateLabelFormats = {
            milliseconds: 'HH:mm:ss.fff',
            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,
            getTemplate: getTemplate,
            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--accent-contrast"></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'));
            mapColor('diagram.shapeDefaults.fill.color', 'accent');
            mapColor('diagram.shapeDefaults.content.color', 'accent-contrast');
            mapColor('diagram.shapeDefaults.connectorDefaults.fill.color', 'normal-text-color');
            mapColor('diagram.shapeDefaults.connectorDefaults.stroke.color', 'accent-contrast');
            mapColor('diagram.shapeDefaults.connectorDefaults.hover.fill.color', 'accent-contrast');
            mapColor('diagram.shapeDefaults.connectorDefaults.hover.stroke.color', 'normal-text-color');
            mapColor('diagram.editable.resize.handles.stroke.color', 'normal-text-color');
            mapColor('diagram.editable.resize.handles.fill.color', 'normal-background');
            mapColor('diagram.editable.resize.handles.hover.stroke.color', 'normal-text-color');
            mapColor('diagram.editable.resize.handles.hover.fill.color', 'normal-text-color');
            mapColor('diagram.selectable.stroke.color', 'normal-text-color');
            mapColor('diagram.connectionDefaults.stroke.color', 'normal-text-color');
            mapColor('diagram.connectionDefaults.content.color', 'normal-text-color');
            mapColor('diagram.connectionDefaults.selection.handles.fill.color', 'accent-contrast');
            mapColor('diagram.connectionDefaults.selection.handles.stroke.color', 'normal-text-color');
            mapColor('diagram.connectionDefaults.selection.stroke.color', 'normal-text-color');
        }());
        (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 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];
            registerTheme('default-v2', {
                chart: {},
                gauge: {
                    pointer: { color: PRIMARY },
                    scale: {
                        rangePlaceholderColor: AXIS,
                        labels: { color: TEXT },
                        minorTicks: { color: TEXT },
                        majorTicks: { color: TEXT },
                        line: { color: TEXT }
                    }
                },
                diagram: {},
                treeMap: { colors: fuse(SERIES, SERIES_LIGHT) }
            });
            themes.sass = themes['default-v2'];
        }());
        (function () {
            var TEXT = '#292b2c';
            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];
            registerTheme('bootstrap-v4', {
                chart: {},
                gauge: {
                    pointer: { color: PRIMARY },
                    scale: {
                        rangePlaceholderColor: AXIS,
                        labels: { color: TEXT },
                        minorTicks: { color: TEXT },
                        majorTicks: { color: TEXT },
                        line: { color: TEXT }
                    }
                },
                diagram: {},
                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 getTemplate = dataviz.getTemplate;
        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 services = dataviz.services;
        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.noteText = data.fields.noteText;
                    if (!defined(point.dataItem)) {
                        point.dataItem = series.data[categoryIx];
                    }
                    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',
                        'content',
                        '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,
                        dataItem: outOfRangePoint.item
                    });
                }
            },
            _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 labelTemplate = getTemplate(labels);
                    var labelText = this.value;
                    if (labelTemplate) {
                        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 labelTemplate = getTemplate(labels);
                    var labelText;
                    if (labelTemplate) {
                        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',
                        'content',
                        '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.visible !== false && 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 ? getTemplate(labels) : getTemplate(inactiveItemsLabels) || getTemplate(labels);
                    if (labelTemplate) {
                        text = 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 visible = axis.options.visible !== false;
                    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));
                        }
                        if (visible) {
                            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));
                        }
                        if (visible) {
                            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 visible$1 = axis$1.options.visible !== false;
                    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));
                        }
                        if (visible$1) {
                            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));
                        }
                        if (visible$1) {
                            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 labelTemplate = getTemplate(options);
                var labelText;
                if (labelTemplate) {
                    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;
                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.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,
                    direction: 'ltr'
                });
                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 box = categoryAxis.pane.chartsBox();
                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: box.width(),
                    height: box.height() + SELECTOR_HEIGHT_ADJUST,
                    padding: {
                        left: paddingLeft,
                        top: paddingTop
                    },
                    offset: {
                        left: box.x1 + paddingLeft,
                        top: box.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 axisOptions = ref.categoryAxis.options;
                var range = state.range;
                var target = state.moveTarget;
                var reverse = axisOptions.reverse;
                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 / (axisOptions.categories.length - 1);
                var offset = Math.round(delta / scale) * (reverse ? -1 : 1);
                if (!target) {
                    return;
                }
                var leftHandle = hasClasses(target, 'k-left-handle');
                var rightHandle = hasClasses(target, 'k-right-handle');
                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 (leftHandle && !reverse || rightHandle && reverse) {
                    range.from = Math.min(Math.max(min, from - offset), max - 1);
                    range.to = Math.max(range.from + 1, range.to);
                } else if (leftHandle && reverse || rightHandle && !reverse) {
                    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 reverse = this.categoryAxis.options.reverse;
                var offset = options.offset;
                var padding = options.padding;
                var border = options.selection.border;
                var left = reverse ? to : from;
                var right = reverse ? from : to;
                var edge = 'x' + (reverse ? 2 : 1);
                var box = this._slot(left);
                var leftMaskWidth = round(box[edge] - offset.left + padding.left);
                elementStyles(this.leftMask, { width: leftMaskWidth });
                elementStyles(this.selection, { left: leftMaskWidth });
                box = this._slot(right);
                var rightMaskWidth = round(options.width - (box[edge] - 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;
                }
            },
            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;
                var labelTemplate = getTemplate(labels);
                if (labelTemplate) {
                    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 || labelText === 0)) {
                    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 ? getTemplate(labelsOptions) : getTemplate(inactiveItemsLabels) || getTemplate(labelsOptions);
                    var text = options.category || '';
                    if (labelTemplate) {
                        text = 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 bindSegments(series) {
            var data = series.data;
            var points = [];
            var sum = 0;
            var count = 0;
            for (var idx = 0; idx < data.length; idx++) {
                var pointData = SeriesBinder.current.bindPoint(series, idx);
                var value = pointData.valueFields.value;
                if (isString(value)) {
                    value = parseFloat(value);
                }
                if (isNumber(value)) {
                    pointData.visible = segmentVisible(series, pointData.fields, idx) !== false;
                    pointData.value = Math.abs(value);
                    points.push(pointData);
                    if (pointData.visible) {
                        sum += pointData.value;
                    }
                    if (value !== 0) {
                        count++;
                    }
                } else {
                    points.push(null);
                }
            }
            return {
                total: sum,
                points: points,
                count: count
            };
        }
        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 ref$1 = bindSegments(currentSeries);
                    var total = ref$1.total;
                    var points = ref$1.points;
                    var count = ref$1.count;
                    var anglePerValue = 360 / total;
                    var constantAngle = void 0;
                    if (!isFinite(anglePerValue)) {
                        constantAngle = 360 / count;
                    }
                    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 < points.length; i++) {
                        var pointData = points[i];
                        if (!pointData) {
                            continue;
                        }
                        var fields = pointData.fields;
                        var value = pointData.value;
                        var visible = pointData.visible;
                        var angle = value !== 0 ? constantAngle || value * anglePerValue : 0;
                        var explode = data.length !== 1 && Boolean(fields.explode);
                        if (!isFunction(currentSeries.color)) {
                            currentSeries.color = fields.color || seriesColors[i % colorsCount];
                        }
                        callback(pointData.valueFields.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 ? value / 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',
                        'content',
                        '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) {
                            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 paddingBox = box.clone().unpad(padding);
                var axisBox = paddingBox.clone();
                axisBox.y2 = axisBox.y1 + Math.min(axisBox.width(), axisBox.height());
                axisBox.align(paddingBox, Y, CENTER);
                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 ref$1 = bindSegments(series);
                var total = ref$1.total;
                var points = ref$1.points;
                for (var i = 0; i < points.length; i++) {
                    var pointData = points[i];
                    if (!pointData) {
                        continue;
                    }
                    var fields = pointData.fields;
                    if (!isFunction(series.color)) {
                        series.color = fields.color || seriesColors[i % seriesColors.length];
                    }
                    fields = deepExtend({
                        index: i,
                        owner: this$1,
                        series: series,
                        dataItem: data[i],
                        percentage: pointData.value / total
                    }, fields, { visible: pointData.visible });
                    var value = pointData.valueFields.value;
                    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',
                        'content',
                        'template',
                        '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) {
                    var labelTemplate = getTemplate(labels);
                    if (labelTemplate) {
                        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.trigger('init');
                        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,
            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',
                init: '_onInit'
            }
        });
        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',
                axisDefaults: {},
                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
                });
            },
            _onInit: function (e) {
                this._instance = e.sender;
            },
            _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.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 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);
                var template = dataviz.getTemplate(options);
                this.clearHideTimeout();
                if (!this._visible) {
                    elementStyles(element, {
                        visibility: 'hidden',
                        display: 'block'
                    });
                    this._visible = true;
                }
                if (template) {
                    text = 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: dataviz.getTemplate(options.hint),
                        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 SASS_THEMES = [
            'sass',
            'default-v2',
            'bootstrap-v4'
        ];
        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;
                var themeName = ((that.options || {}).theme || '').toLowerCase();
                var themes = dataviz.ui.themes || {};
                var themeOptions;
                if (SASS_THEMES.indexOf(themeName) != -1) {
                    themeOptions = dataviz.autoTheme().diagram;
                } else {
                    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.621 (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('aspnetmvc/kendo.data.aspnetmvc', [
        'kendo.data',
        'kendo.combobox',
        'kendo.multiselect',
        'kendo.validator'
    ], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, escapeQuoteRegExp = /'/gi, extend = $.extend, isArray = $.isArray, isPlainObject = $.isPlainObject, POINT = '.';
        function parameterMap(options, operation, serializationOptions) {
            var result = {};
            if (options.sort) {
                result[this.options.prefix + 'sort'] = $.map(options.sort, function (sort) {
                    return sort.field + '-' + sort.dir;
                }).join('~');
                delete options.sort;
            } else {
                result[this.options.prefix + 'sort'] = '';
            }
            if (options.page) {
                result[this.options.prefix + 'page'] = options.page;
                delete options.page;
            }
            if (options.pageSize) {
                result[this.options.prefix + 'pageSize'] = options.pageSize;
                delete options.pageSize;
            }
            if (options.group) {
                result[this.options.prefix + 'group'] = $.map(options.group, function (group) {
                    return group.field + '-' + group.dir;
                }).join('~');
                delete options.group;
            } else {
                result[this.options.prefix + 'group'] = '';
            }
            if (options.aggregate) {
                result[this.options.prefix + 'aggregate'] = $.map(options.aggregate, function (aggregate) {
                    return aggregate.field + '-' + aggregate.aggregate;
                }).join('~');
                delete options.aggregate;
            }
            if (options.filter) {
                result[this.options.prefix + 'filter'] = serializeFilter(options.filter, serializationOptions.encode);
                delete options.filter;
            } else {
                result[this.options.prefix + 'filter'] = '';
                delete options.filter;
            }
            delete options.take;
            delete options.skip;
            var serializer = new Serializer(serializationOptions);
            serializer.serialize(result, options, '');
            return result;
        }
        var Serializer = function (options) {
            options = options || {};
            this.culture = options.culture || kendo.culture();
            this.stringifyDates = options.stringifyDates;
            this.decimalSeparator = this.culture.numberFormat[POINT];
        };
        Serializer.prototype = Serializer.fn = {
            serialize: function (result, data, prefix) {
                var valuePrefix;
                for (var key in data) {
                    valuePrefix = prefix ? prefix + '.' + key : key;
                    this.serializeField(result, data[key], data, key, valuePrefix);
                }
            },
            serializeField: function (result, value, data, key, prefix) {
                if (isArray(value)) {
                    this.serializeArray(result, value, prefix);
                } else if (isPlainObject(value)) {
                    this.serialize(result, value, prefix);
                } else {
                    if (result[prefix] === undefined) {
                        result[prefix] = data[key] = this.serializeValue(value);
                    }
                }
            },
            serializeArray: function (result, data, prefix) {
                var value, key, valuePrefix;
                for (var sourceIndex = 0, destinationIndex = 0; sourceIndex < data.length; sourceIndex++) {
                    value = data[sourceIndex];
                    key = '[' + destinationIndex + ']';
                    valuePrefix = prefix + key;
                    this.serializeField(result, value, data, key, valuePrefix);
                    destinationIndex++;
                }
            },
            serializeValue: function (value) {
                if (value instanceof Date) {
                    if (this.stringifyDates) {
                        value = kendo.stringify(value).replace(/"/g, '');
                    } else {
                        value = kendo.toString(value, 'G', this.culture.name);
                    }
                } else if (typeof value === 'number') {
                    value = value.toString().replace(POINT, this.decimalSeparator);
                }
                return value;
            }
        };
        function serializeFilter(filter, encode) {
            if (filter.filters) {
                return $.map(filter.filters, function (f) {
                    var hasChildren = f.filters && f.filters.length > 1, result = serializeFilter(f, encode);
                    if (result && hasChildren) {
                        result = '(' + result + ')';
                    }
                    return result;
                }).join('~' + filter.logic + '~');
            }
            if (filter.field) {
                return filter.field + '~' + filter.operator + '~' + encodeFilterValue(filter.value, encode);
            } else {
                return undefined;
            }
        }
        function encodeFilterValue(value, encode) {
            if (typeof value === 'string') {
                if (value.indexOf('Date(') > -1) {
                    value = new Date(parseInt(value.replace(/^\/Date\((.*?)\)\/$/, '$1'), 10));
                } else {
                    value = value.replace(escapeQuoteRegExp, '\'\'');
                    if (encode) {
                        value = encodeURIComponent(value);
                    }
                    return '\'' + value + '\'';
                }
            }
            if (value && value.getTime) {
                return 'datetime\'' + kendo.format('{0:yyyy-MM-ddTHH-mm-ss}', value) + '\'';
            }
            return value;
        }
        function valueOrDefault(value, defaultValue) {
            return typeof value !== 'undefined' ? value : defaultValue;
        }
        function translateGroup(group) {
            var hasSubgroups = group.HasSubgroups || group.hasSubgroups || false;
            var items = group.Items || group.items;
            return {
                value: valueOrDefault(group.Key, valueOrDefault(group.key, group.value)),
                field: group.Member || group.member || group.field,
                hasSubgroups: hasSubgroups,
                aggregates: translateAggregate(group.Aggregates || group.aggregates),
                items: hasSubgroups ? $.map(items, translateGroup) : items
            };
        }
        function translateAggregateResults(aggregate) {
            var obj = {};
            obj[aggregate.AggregateMethodName.toLowerCase()] = aggregate.Value;
            return obj;
        }
        function translateAggregate(aggregates) {
            var functionResult = {}, key, functionName, aggregate;
            for (key in aggregates) {
                functionResult = {};
                aggregate = aggregates[key];
                for (functionName in aggregate) {
                    functionResult[functionName.toLowerCase()] = aggregate[functionName];
                }
                aggregates[key] = functionResult;
            }
            return aggregates;
        }
        function convertAggregates(aggregates) {
            var idx, length, aggregate;
            var result = {};
            for (idx = 0, length = aggregates.length; idx < length; idx++) {
                aggregate = aggregates[idx];
                result[aggregate.Member] = extend(true, result[aggregate.Member], translateAggregateResults(aggregate));
            }
            return result;
        }
        extend(true, kendo.data, {
            schemas: {
                'aspnetmvc-ajax': {
                    groups: function (data) {
                        return $.map(this._dataAccessFunction(data), translateGroup);
                    },
                    aggregates: function (data) {
                        data = data.d || data;
                        var aggregates = data.AggregateResults || [];
                        if (!$.isArray(aggregates)) {
                            for (var key in aggregates) {
                                aggregates[key] = convertAggregates(aggregates[key]);
                            }
                            return aggregates;
                        }
                        return convertAggregates(aggregates);
                    }
                }
            }
        });
        extend(true, kendo.data, {
            transports: {
                'aspnetmvc-ajax': kendo.data.RemoteTransport.extend({
                    init: function (options) {
                        var that = this, stringifyDates = (options || {}).stringifyDates;
                        kendo.data.RemoteTransport.fn.init.call(this, extend(true, {}, this.options, options, {
                            parameterMap: function (options, operation) {
                                return parameterMap.call(that, options, operation, {
                                    encode: false,
                                    stringifyDates: stringifyDates
                                });
                            }
                        }));
                    },
                    read: function (options) {
                        var data = this.options.data, url = this.options.read.url;
                        if (isPlainObject(data)) {
                            if (url) {
                                this.options.data = null;
                            }
                            if (!data.Data.length && url) {
                                kendo.data.RemoteTransport.fn.read.call(this, options);
                            } else {
                                options.success(data);
                            }
                        } else {
                            kendo.data.RemoteTransport.fn.read.call(this, options);
                        }
                    },
                    options: {
                        read: { type: 'POST' },
                        update: { type: 'POST' },
                        create: { type: 'POST' },
                        destroy: { type: 'POST' },
                        parameterMap: parameterMap,
                        prefix: ''
                    }
                })
            }
        });
        extend(true, kendo.data, { schemas: { 'webapi': kendo.data.schemas['aspnetmvc-ajax'] } });
        extend(true, kendo.data, {
            transports: {
                'webapi': kendo.data.RemoteTransport.extend({
                    init: function (options) {
                        var that = this;
                        var stringifyDates = (options || {}).stringifyDates;
                        if (options.update) {
                            var updateUrl = typeof options.update === 'string' ? options.update : options.update.url;
                            options.update = extend(options.update, {
                                url: function (data) {
                                    return kendo.format(updateUrl, data[options.idField]);
                                }
                            });
                        }
                        if (options.destroy) {
                            var destroyUrl = typeof options.destroy === 'string' ? options.destroy : options.destroy.url;
                            options.destroy = extend(options.destroy, {
                                url: function (data) {
                                    return kendo.format(destroyUrl, data[options.idField]);
                                }
                            });
                        }
                        if (options.create && typeof options.create === 'string') {
                            options.create = { url: options.create };
                        }
                        kendo.data.RemoteTransport.fn.init.call(this, extend(true, {}, this.options, options, {
                            parameterMap: function (options, operation) {
                                return parameterMap.call(that, options, operation, {
                                    encode: false,
                                    stringifyDates: stringifyDates,
                                    culture: kendo.cultures['en-US']
                                });
                            }
                        }));
                    },
                    read: function (options) {
                        var data = this.options.data, url = this.options.read.url;
                        if (isPlainObject(data)) {
                            if (url) {
                                this.options.data = null;
                            }
                            if (!data.Data.length && url) {
                                kendo.data.RemoteTransport.fn.read.call(this, options);
                            } else {
                                options.success(data);
                            }
                        } else {
                            kendo.data.RemoteTransport.fn.read.call(this, options);
                        }
                    },
                    options: {
                        read: { type: 'GET' },
                        update: { type: 'PUT' },
                        create: { type: 'POST' },
                        destroy: { type: 'DELETE' },
                        parameterMap: parameterMap,
                        prefix: ''
                    }
                })
            }
        });
        extend(true, kendo.data, {
            transports: {
                'aspnetmvc-server': kendo.data.RemoteTransport.extend({
                    init: function (options) {
                        var that = this;
                        kendo.data.RemoteTransport.fn.init.call(this, extend(options, {
                            parameterMap: function (options, operation) {
                                return parameterMap.call(that, options, operation, { encode: true });
                            }
                        }));
                    },
                    read: function (options) {
                        var url, prefix = this.options.prefix, params = [
                                prefix + 'sort',
                                prefix + 'page',
                                prefix + 'pageSize',
                                prefix + 'group',
                                prefix + 'aggregate',
                                prefix + 'filter'
                            ], regExp = new RegExp('(' + params.join('|') + ')=[^&]*&?', 'g'), query;
                        query = location.search.replace(regExp, '').replace('?', '');
                        if (query.length && !/&$/.test(query)) {
                            query += '&';
                        }
                        options = this.setup(options, 'read');
                        url = options.url;
                        if (url.indexOf('?') >= 0) {
                            query = query.replace(/(.*?=.*?)&/g, function (match) {
                                if (url.indexOf(match.substr(0, match.indexOf('='))) >= 0) {
                                    return '';
                                }
                                return match;
                            });
                            url += '&' + query;
                        } else {
                            url += '?' + query;
                        }
                        url += $.map(options.data, function (value, key) {
                            return key + '=' + value;
                        }).join('&');
                        location.href = url;
                    }
                })
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('aspnetmvc/kendo.combobox.aspnetmvc', ['aspnetmvc/kendo.data.aspnetmvc'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui;
        if (ui && ui.ComboBox) {
            ui.ComboBox.requestData = function (selector) {
                var combobox = $(selector).data('kendoComboBox');
                if (!combobox) {
                    return;
                }
                var filter = combobox.dataSource.filter();
                var value = combobox.input.val();
                if (!filter || !filter.filters.length) {
                    value = '';
                }
                return { text: value };
            };
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('aspnetmvc/kendo.dropdownlist.aspnetmvc', ['aspnetmvc/kendo.data.aspnetmvc'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui;
        if (ui && ui.DropDownList) {
            ui.DropDownList.requestData = function (selector) {
                var dropdownlist = $(selector).data('kendoDropDownList');
                if (!dropdownlist) {
                    return;
                }
                var filter = dropdownlist.dataSource.filter();
                var filterInput = dropdownlist.filterInput;
                var value = filterInput ? filterInput.val() : '';
                if (!filter || !filter.filters.length) {
                    value = '';
                }
                return { text: value };
            };
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('aspnetmvc/kendo.multiselect.aspnetmvc', ['aspnetmvc/kendo.combobox.aspnetmvc'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, ui = kendo.ui;
        if (ui && ui.MultiSelect) {
            ui.MultiSelect.requestData = function (selector) {
                var multiselect = $(selector).data('kendoMultiSelect');
                if (!multiselect) {
                    return;
                }
                var text = multiselect.input.val();
                return { text: text !== multiselect.options.placeholder ? text : '' };
            };
        }
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('aspnetmvc/kendo.imagebrowser.aspnetmvc', ['aspnetmvc/kendo.multiselect.aspnetmvc'], f);
}(function () {
    (function ($, undefined) {
        var kendo = window.kendo, extend = $.extend, isFunction = $.isFunction;
        extend(true, kendo.data, {
            schemas: {
                'imagebrowser-aspnetmvc': {
                    data: function (data) {
                        return data || [];
                    },
                    model: {
                        id: 'name',
                        fields: {
                            name: { field: 'Name' },
                            size: { field: 'Size' },
                            type: {
                                field: 'EntryType',
                                parse: function (value) {
                                    return value == 0 ? 'f' : 'd';
                                }
                            }
                        }
                    }
                }
            }
        });
        extend(true, kendo.data, { schemas: { 'filebrowser-aspnetmvc': kendo.data.schemas['imagebrowser-aspnetmvc'] } });
        extend(true, kendo.data, {
            transports: {
                'imagebrowser-aspnetmvc': 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' },
                        parameterMap: function (options, type) {
                            if (type != 'read') {
                                options.EntryType = options.EntryType === 'f' ? 0 : 1;
                            }
                            return options;
                        }
                    }
                })
            }
        });
        extend(true, kendo.data, { transports: { 'filebrowser-aspnetmvc': kendo.data.transports['imagebrowser-aspnetmvc'] } });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('aspnetmvc/kendo.validator.aspnetmvc', ['aspnetmvc/kendo.imagebrowser.aspnetmvc'], f);
}(function () {
    (function ($, undefined) {
        var nameSpecialCharRegExp = /("|\%|'|\[|\]|\$|\.|\,|\:|\;|\+|\*|\&|\!|\#|\(|\)|<|>|\=|\?|\@|\^|\{|\}|\~|\/|\||`)/g;
        function generateMessages() {
            var name, messages = {};
            for (name in validationRules) {
                messages['mvc' + name] = createMessage(name);
            }
            return messages;
        }
        function generateRules() {
            var name, rules = {};
            for (name in validationRules) {
                rules['mvc' + name] = createRule(name);
            }
            return rules;
        }
        function extractParams(input, ruleName) {
            var params = {}, index, data = input.data(), length = ruleName.length, rule, key;
            for (key in data) {
                rule = key.toLowerCase();
                index = rule.indexOf(ruleName);
                if (index > -1) {
                    rule = rule.substring(index + length, key.length);
                    if (rule) {
                        params[rule] = data[key];
                    }
                }
            }
            return params;
        }
        function rulesFromData(metadata) {
            var idx, length, fields = metadata.Fields || [], rules = {};
            for (idx = 0, length = fields.length; idx < length; idx++) {
                $.extend(true, rules, rulesForField(fields[idx]));
            }
            return rules;
        }
        function rulesForField(field) {
            var rules = {}, messages = {}, fieldName = field.FieldName, fieldRules = field.ValidationRules, validationType, validationParams, idx, length;
            for (idx = 0, length = fieldRules.length; idx < length; idx++) {
                validationType = fieldRules[idx].ValidationType;
                validationParams = fieldRules[idx].ValidationParameters;
                rules[fieldName + validationType] = createMetaRule(fieldName, validationType, validationParams);
                messages[fieldName + validationType] = createMetaMessage(fieldRules[idx].ErrorMessage);
            }
            return {
                rules: rules,
                messages: messages
            };
        }
        function createMessage(rule) {
            return function (input) {
                return input.attr('data-val-' + rule);
            };
        }
        function createRule(ruleName) {
            return function (input) {
                if (input.filter('[data-val-' + ruleName + ']').length) {
                    return validationRules[ruleName](input, extractParams(input, ruleName));
                }
                return true;
            };
        }
        function createMetaMessage(message) {
            return function () {
                return message;
            };
        }
        function createMetaRule(fieldName, type, params) {
            return function (input) {
                if (input.filter('[name=' + fieldName + ']').length) {
                    return validationRules[type](input, params);
                }
                return true;
            };
        }
        function patternMatcher(value, pattern) {
            if (typeof pattern === 'string') {
                pattern = new RegExp('^(?:' + pattern + ')$');
            }
            return pattern.test(value);
        }
        var validationRules = {
            required: function (input) {
                var value = input.val(), checkbox = input.filter('[type=checkbox]'), name;
                if (checkbox.length) {
                    name = checkbox[0].name.replace(nameSpecialCharRegExp, '\\$1');
                    var hiddenSelector = 'input:hidden[name=\'' + name + '\']';
                    var hidden = checkbox.next(hiddenSelector);
                    if (!hidden.length) {
                        hidden = checkbox.next('label.k-checkbox-label').next(hiddenSelector);
                    }
                    if (hidden.length) {
                        value = hidden.val();
                    } else {
                        value = input.attr('checked') === 'checked';
                    }
                }
                return !(value === '' || !value || value.length === 0);
            },
            number: function (input) {
                return input.val() === '' || input.val() == null || kendo.parseFloat(input.val()) !== null;
            },
            regex: function (input, params) {
                if (input.val() !== '') {
                    return patternMatcher(input.val(), params.pattern);
                }
                return true;
            },
            range: function (input, params) {
                if (input.val() !== '') {
                    return this.min(input, params) && this.max(input, params);
                }
                return true;
            },
            min: function (input, params) {
                var min = parseFloat(params.min) || 0, val = kendo.parseFloat(input.val());
                return min <= val;
            },
            max: function (input, params) {
                var max = parseFloat(params.max) || 0, val = kendo.parseFloat(input.val());
                return val <= max;
            },
            date: function (input) {
                return input.val() === '' || kendo.parseDate(input.val()) !== null;
            },
            length: function (input, params) {
                if (input.val() !== '') {
                    var len = $.trim(input.val()).length;
                    return (!params.min || len >= (params.min || 0)) && (!params.max || len <= (params.max || 0));
                }
                return true;
            }
        };
        $.extend(true, kendo.ui.validator, {
            rules: generateRules(),
            messages: generateMessages(),
            messageLocators: {
                mvcLocator: {
                    locate: function (element, fieldName) {
                        fieldName = fieldName.replace(nameSpecialCharRegExp, '\\$1');
                        return element.find('.field-validation-valid[data-valmsg-for=\'' + fieldName + '\'], .field-validation-error[data-valmsg-for=\'' + fieldName + '\']');
                    },
                    decorate: function (message, fieldName) {
                        message.addClass('field-validation-error').attr('data-valmsg-for', fieldName || '');
                    }
                },
                mvcMetadataLocator: {
                    locate: function (element, fieldName) {
                        fieldName = fieldName.replace(nameSpecialCharRegExp, '\\$1');
                        return element.find('#' + fieldName + '_validationMessage.field-validation-valid');
                    },
                    decorate: function (message, fieldName) {
                        message.addClass('field-validation-error').attr('id', fieldName + '_validationMessage');
                    }
                }
            },
            ruleResolvers: {
                mvcMetaDataResolver: {
                    resolve: function (element) {
                        var metadata = window.mvcClientValidationMetadata || [];
                        if (metadata.length) {
                            element = $(element);
                            for (var idx = 0; idx < metadata.length; idx++) {
                                if (metadata[idx].FormId == element.attr('id')) {
                                    return rulesFromData(metadata[idx]);
                                }
                            }
                        }
                        return {};
                    }
                }
            }
        });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));
(function (f, define) {
    define('kendo.aspnetmvc', [
        'kendo.data',
        'kendo.combobox',
        'kendo.dropdownlist',
        'kendo.multiselect',
        'kendo.validator',
        'aspnetmvc/kendo.data.aspnetmvc',
        'aspnetmvc/kendo.combobox.aspnetmvc',
        'aspnetmvc/kendo.dropdownlist.aspnetmvc',
        'aspnetmvc/kendo.multiselect.aspnetmvc',
        'aspnetmvc/kendo.imagebrowser.aspnetmvc',
        'aspnetmvc/kendo.validator.aspnetmvc'
    ], f);
}(function () {
    var __meta__ = {
        id: 'aspnetmvc',
        name: 'ASP.NET MVC',
        category: 'wrappers',
        description: 'Scripts required by Telerik UI for ASP.NET MVC',
        depends: [
            'data',
            'combobox',
            'dropdownlist',
            'multiselect',
            'validator'
        ]
    };
    (function ($, undefined) {
        var extend = $.extend;
        $(function () {
            kendo.__documentIsReady = true;
        });
        function syncReady(cb) {
            if (kendo.__documentIsReady) {
                cb();
            } else {
                $(cb);
            }
        }
        extend(kendo, { syncReady: syncReady });
    }(window.kendo.jQuery));
}, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) {
    (a3 || a2)();
}));;
/** 
 * Kendo UI v2017.2.621 (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){
    if (typeof define === 'function' && define.amd) {
        define(["kendo.core"], f);
    } else {
        f();
    }
}(function(){
(function( window, undefined ) {
    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);
}));;
